Announcement Announcement Module
Collapse
No announcement yet.
Access singleton from non-singleton Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

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

    Comment


    • #3
      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.

      Comment


      • #4
        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, 03:22 AM.

        Comment


        • #5
          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.

          Comment


          • #6
            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?

            Comment


            • #7
              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.

              Comment


              • #8
                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, 10:28 AM.

                Comment


                • #9
                  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.

                  Comment


                  • #10
                    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.

                    Comment


                    • #11
                      Hiya

                      Another possible solution would be to use the ServiceLocatorFactoryBean from the Spring Core distribution...

                      http://www.springframework.org/docs/...ctoryBean.html

                      Using this option would mean you get all the goodness of the factory style approach, and only have to write 1) a strongly typed interface, and 2) a wee bit of Spring XML (a bean definition for the SLFB).

                      Ciao
                      Rick

                      Comment


                      • #12
                        Originally posted by Thomas Matzner
                        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.
                        You don`t have to. If the object to create needs some dependencies, it could get the dependencies injected by the factory (a solution I like), or the dependencies can be injected by the class that need an instance.

                        example:
                        Code:
                        class SomeClass{
                             FooDao _dao;
                             SomeClass(FooDao dao){
                                 _dao = dao;
                             } 
                        
                             void foo(){
                                  C c = new C(_dao);
                                  ..do something with c.
                             }
                        }

                        Comment


                        • #13
                          Although all of the solutions seem correct, I think the problem is being presented backwards.

                          Sometimes, however, I'd like to access a SomeDao operation from an object of a non-singleton class C.
                          So you have an object C that is not a singleton, and it depends on some bean (that is a singleton)?
                          I think the issue comes up when a singleton bean depends on a non-singleton bean. The reason being that even if you set the singleton attribute to false on the non-singleton, the singleton object is only injected with the non-singleton reference once.

                          Comment

                          Working...
                          X