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

Thread: Access singleton from non-singleton

  1. #1
    Join Date
    Aug 2005
    Location
    München, Germany
    Posts
    24

    Default Access singleton from non-singleton

    I created my DAOs as plain-vanilla singletons, with other singleton classes, mostly controllers, just declaring the interface, say SomeDao, and getting the implemented class, say HibernateSomeDao, injected. Nothing special there.

    Sometimes, however, I'd like to access a SomeDao operation from an object of a non-singleton class C. I'd like to avoid the following two easy solutions:

    - Just instanciating a new object of the HibernateSomeDao class inside C -- because this would make C dependent on the HibernateSomeDao class instead of the SomeDao interface.

    - Getting the someDao object from the bean factory -- because this would clutter my class C code with calls to the Spring framework.

    I think both arguments are in accordance with the Spring literature.

    Therefore, I found the following little solution: I created a class DaoUtils that looks like this:

    public class DaoUtils {
    static protected SomeDao someDao;

    public static SomeDao getSomeDao() {
    return DaoUtils.someDao;
    }

    public void setSomeDao(SomeDao someDao) {
    DaoUtils.someDao = someDao;
    }

    }

    To give someDao the correct value, I instanciate this in my application-context xml. Now, I can access the correct Dao from everywhere in my application by just saying DaoUtils.getSomeDao().

    While this appears to work well, I am still a little bit puzzled:

    1. When searching in all available Spring books, and in this forum, I didn't find this problem discussed. Is no one else besides me having it?

    2. The solution looks a little bit like cheating. I let the container create an instance of DaoUtils, although this instance isn't really used, because the class doesn't have any instance variables. Instead, the instance just serves to set the class variable. Not quite the sort of code you get taught in a software engineering lecture. Therefore:

    3. Did I miss an easier solution for this? The closest thing I saw described might be configuring a prototype object for class C that contains the reference to SomeDao. However, this would clutter the code of the caller that instantiated C with calls to the Spring framework.

  2. #2
    Join Date
    Jan 2005
    Location
    Bucharest, Romania
    Posts
    5,403

    Default

    Why use a repository/lookup class (DaoUtils) when you can simply inject the someDao into your classes. Just declare a field and a setter and inject the someDao. No matter how you put it you have to get a hold of getSomeDao - using Spring is better because you don't reply on static code for your colaborators which makes the class easy to test.
    Costin Leau
    SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
    http://twitter.com/costinl
    Please use [ c o d e ] [ / c o d e ] tags

  3. #3
    Join Date
    Aug 2005
    Location
    München, Germany
    Posts
    24

    Default

    Thanks for the hint, Costin, but that's the trick I'm missing somehow. All the examples I see inject values into singletons, at startup time. I'd need to declare an inject that should be done implicitly everytime a C instance is created during runtime.

  4. #4
    Join Date
    Nov 2004
    Location
    Hilversum - The Netherlands
    Posts
    1,054

    Default

    Quote Originally Posted by Thomas Matzner
    Thanks for the hint, Costin, but that's the trick I'm missing somehow. All the examples I see inject values into singletons, at startup time. I'd need to declare an inject that should be done implicitly everytime a C instance is created during runtime.
    So you have an object C that is not a singleton, and it depends on some bean (that is a singleton)?

    One solution is creating a C factory, example:

    Code:
    class CFactory{
         SomeDao _someDao;
    
         CFactory(SomeDao someDao){
             _someDao = someDao;
         }
     
         C void create(){
              return new C(_someDao);
         }
    }
    
    class ObjectThatNeedsC{
        private CFactory _cfactory;
       
        ObjectThatNeedsC(CFactory cfactory){
            _cfactory = cfactory;
        }
    
        void someOperation(){
             C c = _cfactory.create();
             ..do you stuff
        }
    }
    And Spring code:

    Code:
    <bean id="someDao" class="SomeDao"/>
    
    <bean id="cFactory" class="CFactory">
         <constructor-arg ref="someDao"/>
    </bean>
    
    <bean id="someObjectThatNeedsC" class="SomeObjectThatNeedsC">
         <constructor-arg ref="cFactory"/>
    </bean>
    You could also have a look at:
    method injection
    I don`t know how to feel about method injection. You have possibility to add some kind of behaviour (that can access the Spring context) to a class and the class won`t depend on Spring (it doesn`t need any imports) but the class has some strange semantics. That is why I don`t use method-injection (it could be that I`m missing something but at moment I would rather use a factory than method injection).
    Last edited by Alarmnummer; Oct 28th, 2005 at 02:22 AM.

  5. #5
    Join Date
    Aug 2004
    Location
    San Mateo, CA
    Posts
    1,265

    Default

    I agree that you must understand what method injection (lookup method) is doing under the covers, but it's a good approach and I would recommend it for this scenario. No Spring dependency.
    Rod Johnson - GM, SpringSource Division, VMware
    http://www.springsource.com
    Spring From the Source

  6. #6
    Join Date
    Nov 2004
    Location
    Hilversum - The Netherlands
    Posts
    1,054

    Default

    Quote Originally Posted by Rod Johnson
    I agree that you must understand what method injection (lookup method) is doing under the covers, but it's a good approach and I would recommend it for this scenario. No Spring dependency.
    But there are some problems. Method injection creates a new proxy with the overriden method, but the orginal class has the original method (so in the original class the method is useless).

    And if you don`t want to depend on Spring, what use does the method have? You create some kind of Spring-import independant construction, but the functionality is provided by Spring, so what use does the method have outside Spring?

  7. #7
    Join Date
    Aug 2005
    Location
    München, Germany
    Posts
    24

    Default

    Thanks for both hints. I'll have to do some studies during the weekend to find out about their implications.

    Concerning Alarmnummer's solution, I'd not like any classes that need C to have to know about this situation. After all, C should shield any caller from its inner workings. Also, if the classes needing C would have to be singletons to be able to receive that DI, that would be a major restriction.

    Concerning method injection, both the Spring reference manual and the "Professional Java Dev..." book claim it can be used if a singleton uses a non-singleton. I need it the other way round, however. But I'll have a closer look at the examples to see if I can make them work for my purposes.

  8. #8
    Join Date
    Nov 2004
    Location
    Hilversum - The Netherlands
    Posts
    1,054

    Default

    Quote Originally Posted by Thomas Matzner
    Thanks for both hints. I'll have to do some studies during the weekend to find out about their implications.

    Concerning Alarmnummer's solution, I'd not like any classes that need C to have to know about this situation. After all, C should shield any caller from its inner workings.
    Yes.. and that is exactly what you get with a Factory. Nobody knows how the factory works and how the dependencies are injected into that factory.

    Maybe it was better if I had written down the factor interface and the implementation (but usually I don`t because I think every knows you should design from an interface).

    so the same example:
    Code:
    interface CFactory{
       C create();
    }
    
    class CFactoryImpl implements CFactory{
         SomeDao _someDao;
    
         CFactory(SomeDao someDao){
             _someDao = someDao;
         }
     
         C create(){
              return new C(_someDao);
         }
    }
    Also, if the classes needing C would have to be singletons to be able to receive that DI, that would be a major restriction.
    They don`t need to be singleton.
    If an object is a singleton, I build it from Spring.
    If an object isn`t a singleton, I build the object from a factory, build the factory in Spring and inject the dependencies into the Factory (and the factory injects it into every instance). Or I create a new object and inject all the dependencies into the newly created object because the environment where the object is created, has all the required dependencies.

    I think you have to give a better example what you want because I don`t have access to my crystal ball today.
    Last edited by Alarmnummer; Oct 28th, 2005 at 09:28 AM.

  9. #9
    Join Date
    Sep 2004
    Location
    Texas
    Posts
    155

    Default

    I run into this situation quite a lot, and I also use Alarmnummer's CFactory interface/implementation approach. When Spring 1.3/AspectJ 5 comes out, you will be able to directly wire instances of your C object, so this problem will go away.

    I dislike introducing a static dependency on a concrete class (DaoUtils), and I don't think method injection is the best solution for this problem.
    Corby

  10. #10
    Join Date
    Aug 2005
    Location
    München, Germany
    Posts
    24

    Default

    No need of a crystal ball, I think we are talking about quite the same task.

    It's just that I don't want to use the factory pattern everywhere, for every little object in my app. I have about 50 classes that are non-singletons, and writing a factory for each of those would be quite an effort. Of course, not all my classes have that problem that I described for class C. But as the callers that want to instantiate C don't know which classes are of the C-type, they would consequently have to use factories for everything.

    The factory mechanism is useful, but even the gurus who wrote Pet Clinic etc. don't go so far as to write factories everywhere. They just instantiate Pet pet = new Pet()

    Thanks to everyone who contributed -- I now have what I wanted: a collection of solutions together with their pros and cons.

Posting Permissions

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