Announcement Announcement Module
Collapse
No announcement yet.
Accessing the ApplicationContext directly... Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Accessing the ApplicationContext directly...

    Hi All,
    I'm in the process of converting an existing app to use the Spring's DI features. I want to access the ApplicationContext the "bad" way while I'm in the process of converting the app.

    Specifically, I want to change the class from:
    Code:
    public class Foo {
        private static Foo instance = new Foo();
    
        public static Foo getInstance() {
            return instance;
        }
    }
    to something like:
    Code:
    public class Foo {
        public Foo getInstance() {
            return (Foo) ApplicationContext.getBean("foo");
        }
    }
    I know it's horrible but it's only temporary...

    I've been hunting around in the docs for a while and came accross SingletonBeanFactoryLocator but couldn't really figure it out. I was hoping for something like WebApplicationContext.getWebApplicationContext(Ser vletContext sc).

    It's just a simple webapp with one applicationContext.xml file in the WEB-INF directory...

    Does anyone have any clues?

  • #2
    In our app, we wrap the ApplicationContext object with a "traditional" singleton. This is our service locator. It creates the context during its own initialization and delegates getter operations to it.

    Comment


    • #3
      For the code in your example, would the Foo object be managed by Spring?

      I think (without writing some code) you could do this:

      Code:
      public class Foo implements ApplicationContextAware
      {
         ApplicationContext ac;
      
         public void setApplicationContext(ApplicationContext ac)
         {
            this.ac = ac;
         }
      
          public Foo getInstance()
          {
              return (Foo) ac.getBean("foo");
          }
      }
      I know this works with the Controller classes, but I haven't tried it with a regular bean. When I've done this with the Controllers, they get automatically injected with the ApplicationContext because they implement the "ApplicationContextAware" interface.

      Comment


      • #4
        The Foo class is managed by spring, but access to the class in a majority of the code uses the getInstance() method. I was hoping to get parts of the app working with spring while others still use the "old" singleton approach but access the spring instance...

        michael, I don't think your approach will work. The getInstance() method is static and can't access the non-static ApplicationContext member variable. I unfortunely left that out of the out of the example. It should have looked like:
        Code:
        public class Foo {
            public static Foo getInstance() {
                return (Foo) ApplicationContext.getBean("foo");
            }
        }
        Cheers,
        Dan

        Comment


        • #5
          Someone from the mailing list came up with an alternate solution to my problem. Instead of accessing the application context staticly change the code to something like this:
          Code:
          public class Foo {
              private static Foo instance = new Foo();
          
              public static Foo getInstance() {
                  return instance;
              }
          
              publis static void setInstacne(Foo newInstance) {
                  instance = newInstance;
              }
          
              public Foo() {
                  Foo.setInstance(this);
              }
          }
          It's not pretty but it will work until I get the rest of the app using DI.

          Cheers,
          Dan

          Comment


          • #6
            Dan, depending on what you are doing you might also look into the:

            org.springframework.beans.factory.BeanFactoryAware interface

            or the org.springframework.beans.factory.access.BeanFacto ryBootstrap
            class (I've never used this one, but it migh get you the access you need).

            Comment


            • #7
              Originally posted by Dan Washusen
              Someone from the mailing list came up with an alternate solution to my problem. Instead of accessing the application context staticly change the code to something like this:
              Code:
              public class Foo {
                  private static Foo instance = new Foo();
              
                  public static Foo getInstance() {
                      return instance;
                  }
              
                  publis static void setInstacne(Foo newInstance) {
                      instance = newInstance;
                  }
              
                  public Foo() {
                      Foo.setInstance(this);
                  }
              }
              Hi Dan,

              I'm going through a similar conversion of an existing app (mine's a Swing app...how about yours?). I have the same problem of how to convert existing singletons to use DI. My first stage of the conversion involved converting my singletons to look very similar to your Foo example. So you should get some reassurance from that. Note that your example is also somewhat similar to Spring Rich Client's Application class, in that it allows singleton-style access while also supporting IOC instantiation.

              In the second stage of the conversion, I instantiated my singletons in the IOC. That is, I declared them as beans in my app context. So far so good. At this point, I now have the potential to make any class that formerly depended on a specific singleton class depend on its interface(s) instead. I can also configure the singletons in the app context config file. An improvement, I think.

              In the third stage of the conversion, which I am starting now, I plan to change all singleton references from a specific singleton to a single singleton, namely Spring Rich's Application class. For example:

              Instead of this:
              MyServiceImpl.getInstance().someMethod()

              I will do this:
              (MyService) Application.services().getBean("MyService")

              Or perhaps even this:
              (MyService) Application.services().getBean("MyService", MyService.class)

              While this will still be singleton access, at least I'll be down to one singleton instead of several and it will also be easier to make the dependent classes depend on each singleton's interface instead of its implementation.

              In the fourth stage of the conversion, I'll remove each singleton's static fields and methods that are used for instance management; essentially this will convert the singletons to non-singletons.

              In the fifth stage, I will convert as many dependent classes as possible to use DI instead of Application.services().getBean(). I'm not sure if 100% conversion is feasible here.

              I hope this helps.

              Comment


              • #8
                Just a comment on the service locator pattern:

                The problem with service locator is your class is now dependent on the locator's and its lookup strategy, of course. This might not be bad, but it certainly can be. Particularly:

                - If there is no way to externalize the initialization and parameterization of the locator's services to replace registered service implementations with mocks or stub implementations, you quickly get a mess. You often must initialize the world just to test your code that needs those services. This is very much a pain if those services use a DB or other expensive resource (or they themselves depend on other hard-coded implementations, producing a chain of initialization pre-requisites). It's much better if you externalize service initialization and configuration logic -- e.g let Spring handle it. You can then provide a convenient means of accessing those services (e.g a static) if you need it, for example, in a standalone application with a lot of fine grained objects.

                - Also, if you're developing framework code that's to be used in a standalone fashion in other environments by other groups of people, you really have to be careful making assumptions about how people will use your code. In Spring Rich we have to be very thoughtful of making our libraries easily usable in standalone fashion with minimal hassel. You simply make standalone usage more difficult when you start making static locator calls from within framework code...as you're forcing the user of the API to initialize the static locator first.

                Keith

                Comment


                • #9
                  Keith, thanks for the comments. Do you have any specific advice on how to refactor mine and Dan's apps, which currently make heavy use of custom singletons? I mean, is my five stage plan all wrong? I know DI is highly recommended but how do I get from here to there without having to turn the app upside down all at once? This seems to be a common problem that several Spring users are having to deal with.

                  Comment


                  • #10
                    A humble idea

                    I am in the same boat right now - singletons everywhere. I am also not in a webapp either - mine lives in the EJB container (much fun), with Statefull Session beans to boot. Here is what I am doing . .

                    1. Built a SpringUtil singleton to initialize and access my spring mounted beans, using SingletonBeanFactoryLocator.
                    2. Converted a singleon objects into interface and impl classes, and mounted them into Spring.
                    3. Each caller/client of the ex-singleton object got changed to maintain an instance variable for that object's new interface, and a getter and setter for that instance variable.
                    4. Modified the constructor of the caller/client class to use the SpringUtil class to get the ex-singleton and call the appropriate setter, and modified the rest of the class to use the instance variable.
                    5. Removed the singleton related code from the ex-singleton.
                    6. Look at the caller/client class as a potential class to move into Spring.

                    This worked for me for a couple of reasons:
                    1. I had to instantiate the BeanFactory myself (no web application).
                    2. It provided me with one "master" singleton into Spring.
                    3. The steps are nice small refactors, a few minutes each.
                    4. It is self-perpetuating and feels very organic. By altering the caller/client, that class moves closer to being suitable to be mounted into Spring itself. I just keep following the object graph, moving things into Spring, getting more DI each time.

                    That's just how I am doing it. Good luck.

                    Comment


                    • #11
                      Thanks for the tips, mmcbudda. It's nice to know that there are others out there who are in the same boat. Your plan sounds rational to me.

                      Comment

                      Working...
                      X