Announcement Announcement Module
Collapse
No announcement yet.
Evil Singleton and IOC Container Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Evil Singleton and IOC Container

    How to refactor existing singletons (i.e. old school singleton, not Spring's "singleton" beans) so that their instance can be instantiated and configured by Spring IOC container but legacy code can still access them in usual way (i.e. mysingleton.getInstance())? We have lot of legacy code that I don't have time right now to refactor to use dependency injection but still want to use IOC to make easy configure of singleton instance.

  • #2
    Stefano,

    Here's some of the code for the Application class in Spring Rich. It supports constructon using a bean factory but also "old school" singleton access via the instance() method.

    Code:
    public class Application  {
    
        private static Application SOLE_INSTANCE;
    
        public static void load(Application instance) {
            SOLE_INSTANCE = instance;
        }
    
        public static Application instance() {
            Assert.state(isLoaded(),
                            "The global rich client application instance has not yet been initialized; it must be created and loaded first.");
            return SOLE_INSTANCE;
        }
    
        public static boolean isLoaded() {
            return SOLE_INSTANCE != null;
        }
    
        public Application(ApplicationLifecycleAdvisor advisor) {
            load(this);
        }
    
        public void setDescriptor(ApplicationDescriptor descriptor) {
            this.descriptor = descriptor;
        }
    
        public void setServices(ApplicationServices services) {
            this.services = services;
        }
    
        private void setLifecycleAdvisor(ApplicationLifecycleAdvisor advisor) {
            this.lifecycleAdvisor = advisor;
        }
    
    ...

    HTH

    Ollie

    Comment


    • #3
      Spring has a special FactoryBean called MethodInvokingFactoryBean that allows to configure old-style singletons as factory beans inside your ApplicationContext.

      Comment


      • #4
        Originally posted by oliverhutchison
        Here's some of the code for the Application class in Spring Rich. It supports constructon using a bean factory but also "old school" singleton access via the instance() method.

        Code:
        public class Application  {
        
            private static Application SOLE_INSTANCE;
        
            public static void load(Application instance) {
                SOLE_INSTANCE = instance;
            }
        
            public static Application instance() {
                Assert.state(isLoaded(),
                                "The global rich client application instance has not yet been initialized; it must be created and loaded first.");
                return SOLE_INSTANCE;
            }
        
            public static boolean isLoaded() {
                return SOLE_INSTANCE != null;
            }
        
            public Application(ApplicationLifecycleAdvisor advisor) {
                load(this);
            }
        
            // various setters for dependency injection
            // ...
        Okay, thank you for this one. I wondering though. Exception is thrown if you try to call instance() before singleton is instantiated. This is good. But I think maybe problem is you can instantiate this singleton more than once, replacing SOLE_INSTANCE every time. If someone (they don't know what they doing) accidentally instantiate this singleton again after container has done it, then maybe it not intialized correctly (when someone else instantiate after container, maybe he is not calling required setters...so singleton has bad state).

        Maybe is better to modify constructor like this to prevent multiple instantiation:
        Code:
        public Application(ApplicationLifecycleAdvisor advisor) {
          // prevent multiple instantiation
          Assert.state(
             !isLoaded(),
            "The global rich client application instance can only be instantiated once."); 
        
          load(this);
        }
        What you thinking about this? I am crazy guy?

        Comment


        • #5
          Originally posted by irbouho
          Spring has a special FactoryBean called MethodInvokingFactoryBean that allows to configure old-style singletons as factory beans inside your ApplicationContext.
          Thanks irbouho. I just read javadoc for that one. Seems interesting. I see I can do this to make container instantiate old style singleton:
          Code:
          <bean id="mySingleton" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
              <property name="staticMethod"><value>com.whatever.MySingleton.getInstance</value></property>
          </bean>
          That is a start. Now how to declaratively inject dependencies into this singleton? I want the container to call various setters after instantiation to inject dependencies.

          Comment


          • #6
            Originally posted by steve_smith
            That is a start. Now how to declaratively inject dependencies into this singleton? I want the container to call various setters after instantiation to inject dependencies.
            Aha! I look yet again at reference docs. Maybe factory-method better than MethodInvokingFactoryBean for injecting dependency into such singleton:

            Code:
            <bean id="mySingleton" class="mypackage.MySingleton" factory-method="getInstance">
                <property name="someConfigSetting">
                    <value>foo</value>        
                </property>
                <property name="someCollaborator">
                    <ref bean="someBean"/>
                </property>
            </bean>
            MySingleton have private constructor and static getInstance method like usual old style singleton. MySingleton also have instance methods setSomeConfigSetting and setSomeCollaborator for dependency injection.

            What you thinking about this one? I am crazy guy? I think is working well.

            Comment


            • #7
              Sure, factory-method is the shortest way to configure an old style singleton and set its properties. The only issue I can think of is to make attention the singleton is not used by non Spring managed classes before it has been intialized by Spring.

              Comment


              • #8
                If you think it's a good idea to throw an exception if the singleton is already populated then once go for it! You're quite right - it would be extremely easy to accidentally instantiate the singleton again and overwrite the original.

                With respect to using the factory-method support, IMO you'd be better of relying on Spring to do the instantiation and the initialization. Otherwise, as Omar's pointed out, you could accidentally access your singleton before initialization. It's also a little bit confusing when you're looking through the code and you see the instantiation but not any of the initialization, though a comment or two usually helps in that situation.

                Ollie

                Comment


                • #9
                  Originally posted by oliverhutchison
                  You're quite right - it would be extremely easy to accidentally instantiate the singleton again and overwrite the original.

                  With respect to using the factory-method support, IMO you'd be better of relying on Spring to do the instantiation and the initialization. Otherwise, as Omar's pointed out, you could accidentally access your singleton before initialization.
                  Okay, Ollie, so this is what you suggesting?:
                  1) Get Spring to do instantiation and initialization (i.e. do NOT use factory-method or MethodInvokingFactoryBean).
                  2) Throw exception in getInstance() if instance not yet created, like you did in Application.instance().
                  3) Throw exception in constructor if try to instantiate more than one instance (like I suggest above) -- this way someone cannot accidentally instantiate the singleton again and overwrite the original.

                  If not right interpretation, please tell.

                  Comment

                  Working...
                  X