Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: Accessing the ApplicationContext directly...

  1. #1
    Join Date
    Sep 2004
    Location
    Melbourne, Australia
    Posts
    54

    Default 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. #2

    Default

    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.

  3. #3

    Default

    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.

  4. #4
    Join Date
    Sep 2004
    Location
    Melbourne, Australia
    Posts
    54

    Default

    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

  5. #5
    Join Date
    Sep 2004
    Location
    Melbourne, Australia
    Posts
    54

    Default

    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

  6. #6
    Join Date
    Aug 2004
    Location
    Auburn, AL, USA.
    Posts
    106

    Default

    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).

  7. #7
    Join Date
    Sep 2004
    Location
    Vancouver, BC, Canada
    Posts
    135

    Default

    Quote 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.
    Cheers,
    Joe
    "All your bean are belong to us" - Spring Framework's IOC Container

  8. #8
    Join Date
    Aug 2004
    Location
    Melbourne, FL
    Posts
    2,794

    Default

    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
    Keith Donald
    Core Spring Development Team

  9. #9
    Join Date
    Sep 2004
    Location
    Vancouver, BC, Canada
    Posts
    135

    Default

    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.
    Cheers,
    Joe
    "All your bean are belong to us" - Spring Framework's IOC Container

  10. #10
    Join Date
    Jan 2005
    Posts
    4

    Default 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.

Similar Threads

  1. Accessing ResultSet directly?
    By emartin in forum Data
    Replies: 6
    Last Post: Sep 19th, 2005, 02:53 AM
  2. Replies: 2
    Last Post: May 29th, 2005, 05:22 AM
  3. Obtaining ApplicationContext for web and batch apps
    By Thomas Vaught in forum Container
    Replies: 10
    Last Post: May 23rd, 2005, 07:09 AM
  4. Replies: 8
    Last Post: Apr 11th, 2005, 02:33 PM
  5. Replies: 1
    Last Post: Nov 23rd, 2004, 09:26 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •