Announcement Announcement Module
Collapse
No announcement yet.
getting Spring-instantiated bean in a non-spring bean Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • getting Spring-instantiated bean in a non-spring bean

    Hi, I am a little confused about how to achieve this scenario using spring:

    I have some beans that are getting instantiated during startup by the container using dependency injection. Now I need to use those beans in other classes that could be instantiated by the client without spring e.g by simply doing new()..

    For example, I have a bean A that is being instantiated by spring (singleton.) Now I have another object B that needs A (I know that A has been instantiated at container startup...) I have a reference of A in B. Now I want to get that instance of A in B (after startup.)


    Any idea how I can achieve this?
    Thanks!
    Dipita

  • #2
    If you can't let Spring inject it, you must inject it yourself

    The simplest thing I can think of is injecting it yourself.

    Assuming you have a setter operation on your non-Spring bean class...
    Code:
    SomeType springBean = (SomeType)ctx.getBean("mySpringBean");
    SomeOtherType nonSpringBean = new SomeOtherType();
    nonSpringBean.setSomeType(springBean);
    Spring isn't exactly magical. These steps are basically what Spring is doing under the hood. You can do the same.

    Comment


    • #3
      Thanks gregturn!
      However, the thing that I am not understanding is how I get the ctx?

      I guess I'm unclear when I do org.springframework.context.ApplicationContext ctx = new ApplicationContext("xyz.xml") - is it creating a new instance of the context? I don't want to do that - I want to use the existing context..

      How do I get the existing context? It could be created by some other module somewhere??

      Thanks!
      Dipita


      Originally posted by gregturn View Post
      The simplest thing I can think of is injecting it yourself.

      Assuming you have a setter operation on your non-Spring bean class...
      Code:
      SomeType springBean = (SomeType)ctx.getBean("mySpringBean");
      SomeOtherType nonSpringBean = new SomeOtherType();
      nonSpringBean.setSomeType(springBean);
      Spring isn't exactly magical. These steps are basically what Spring is doing under the hood. You can do the same.

      Comment


      • #4
        I'm assuming you bootstrapped your app

        Are you running a web app, a stand along server app, or a thick client app?

        If you are running a web app, check out http://static.springframework.org/sp...context-create
        and
        http://forum.springframework.org/sho...icationContext

        If you are running a stand-alone server app, you need some type of boot strapping code:
        Code:
        import org.springframework.context.support.AbstractApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        public final class Boot {
        
            public static void main(final String[] args) throws Exception {
                AbstractApplicationContext ctx
                    = new ClassPathXmlApplicationContext(new String []{"beans.xml"});
        
                // add a shutdown hook for the above context... 
                ctx.registerShutdownHook();
        
                // app runs here...
        
                // main method exits, hook is called prior to the app shutting down...
            }
        }
        If you are running a thick client app, then that would be very similar to a boot strapping server app.

        Comment


        • #5
          hi gregturn,
          We are developing a module that could be used as a .jar in another application so I cannot intantiate it the way you are saying. I was thinking that by the time I need this data, the spring context is already instantiated and loaded (either by the main application, or the test in my case,) so I just want to get that context but don't know how to do that..

          Any ideas?
          Dipita

          Comment


          • #6
            Have you had a look at this?
            http://www.springframework.org/docs/...and-singletons

            Comment


            • #7
              Someone has to bootstrap it

              To me, it appears someone, somewhere must bootstrap the application context. They should make the context reachable through a getter. Then you can "get" it and use it. I don't really write web apps, so I'm not that familiar with the servlet-based application context process. I deal with thick client/server apps. Instead of using mystical finder classes, I prefer to bootstrap the IoC container, and if necessary, publish the context to others that may need it through an interface. Seems like the most straightforward thing I can think of.

              Comment


              • #8
                Originally posted by gregturn View Post
                ...I prefer to bootstrap the IoC container, and if necessary, publish the context to others that may need it through an interface. Seems like the most straightforward thing I can think of.
                And is absolutely not in spirit of Spring and dependency injection - you pull context from outside and it is not pushed to you.

                So the proper way seems to provide interface throw which application context may be passed to you (some kind of init-method). Then bootstrapping code calls you providing context in question.

                Comment


                • #9
                  Take that up with Dipita

                  I'm answering Dipita's question. I told him about bootstrapping the IoC container. He pushed back saying someone else is building a jar file and doing the bootstrapping.

                  If everything is getting bootstrapped at the same time, then yes, you can push/DI the context into other places. Spring even has an interface, ApplicationContextAware, to automatically give you the app context. However, if that is not the case, and instead he starts later than the IoC container's startup cycle, he will have to pull it from some type of interface that exposes a "getter".

                  We can't answer one way of the other until Dipita provides more concrete requirements or description of his configuration.

                  Comment


                  • #10
                    Even if he starts later some calling code exists and it may be stated as requirment for calling code to provide context to him.

                    BTW, quite good alternative may be using of AspectJ and @Configurable annotation on his classes.

                    But you are absolutely right saying
                    We can't answer one way of the other until Dipita provides more concrete requirements or description of his configuration.[/

                    Regards,
                    Oleksandr

                    Comment


                    • #11
                      Thanks for repsonding.

                      This is the what is happening in my environment: I am developing a module (which will probably be a .jar) which will be used as part of another application. I will specify some stuff that needs to happen at container startup through a spring context configuration file which the user of this jar will have to use to instantiate the bean. Now what I want the following: I have a class A (singleton class) that has some parameters that get set at startup time, then I have a class B (prototype) that needs the parameters in class A. The thing is that I am trying to figure out how to get the instance of A to use in B. So no matter how B is instantiated, it should always get the instance of A to get the parameters set at startup time.

                      I have been reading the reference and feel this would be best addressed by method injection but I am unclear how to get the beanFactory injected to my bean of class B.

                      I looked at the reference - http://static.springframework.org/sp...thod-injection but don't understand how to get the following code:
                      Code:
                      // a class that uses a stateful Command-style class to perform some processing
                      package fiona.apple;
                      
                      // lots of Spring-API imports
                      import org.springframework.beans.BeansException;
                      import org.springframework.beans.factory.BeanFactory;
                      import org.springframework.beans.factory.BeanFactoryAware;
                      
                      public class CommandManager implements BeanFactoryAware {
                      
                         private BeanFactory beanFactory;
                      
                         public Object process(Map commandState) {
                            // grab a new instance of the appropriate Command
                            Command command = createCommand();
                            // set the state on the (hopefully brand new) Command instance
                            command.setState(commandState);
                            return command.execute();
                         }
                      
                         // the Command returned here could be an implementation that executes asynchronously, or whatever
                         protected Command createCommand() {
                            return (Command) this.beanFactory.getBean("command"); // notice the Spring API dependency
                         }
                      
                         public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
                            this.beanFactory = beanFactory;
                         }
                      }
                      but how does the config file look for this - where do you set the beanFactory?

                      Any help is appreciated?
                      Thanks!
                      Dipita

                      Comment


                      • #12
                        Hi,
                        I managed to figure out how to get method injection to work but it doesn't seem to solve my problem:
                        Code:
                        class A { //singleton class
                          String a;
                        }
                        
                        class B { //prototype class
                           A a;
                           String b;
                           public B createB() { //for method lookup
                               return null;
                           }
                        }
                        
                        config file:
                        <bean id="A" class="A" scope="singleton">
                          <property name="a" value="abc" />
                        </bean>
                        
                        <bean id="B" class="B" scope="prototype" >
                            <property name="b" value="xyz" />
                             <lookup-method name="createB" bean="A" />
                        </bean>
                        Now if the client does this:
                        B b = ctx.getBean("B"); //then all works fine - A gets set properly in B etc.

                        However, if client does this:
                        B b = new B(); //then A doesn't get set. //I want to be able to do this an still have A set correctly in B. In my situation, I want to be able to do this since not everyone will have the ctx.. Or how do I pass/get the context???


                        I somehow want the instance of the bean A (since it's singleton and it's instantiated via DI in spring, I was thinking there should be a way for me to get an instance of A..) - how do I do this in spring?? I tried to implment BeanAwareInterface but my beanFactory is not getting set - I'm not sure how to set/get the bean factory - any examples that are more detailed than the reference would help or any tips on how I can get this to work is very much appreciated!



                        Dipita
                        Last edited by Dipita; Sep 7th, 2007, 02:06 AM.

                        Comment


                        • #13
                          Sure, as Spring does no magic it can not control creation of objects with new operator and such objects will not be injected.

                          To achive your goal you need not Spring, but some true AOP implementation that instruments your class byte code (statically, during compilation or dynamicalyy, during class loading), e. g. AspectJ. Then you shall write aspect that runs after construction of object of your class and inject it. In this part Spring can help you, as it proves @Configurable annotation (which I already have mentioned in one of my posts in this thread), look part 6.8.1 of Spring reference it describes its usage in conjuction with AspectJ pretty detailed.

                          And I want to stress one more - if you want injection of objects created not by container, by directly by new true AOP is your only choice. Otherwise you shall obtain objects from container with getBean() if you want them to be injected.

                          Regards,
                          Oleksandr
                          Last edited by al0; Sep 7th, 2007, 11:08 AM. Reason: Mistyping

                          Comment


                          • #14
                            Hi Oleksandr,
                            Thanks very much! I'll try AOP and see if that does the trick.

                            Dipita

                            Comment


                            • #15
                              In simplest terms you want to inject a singleton object into a prototype object.

                              Apart from method-injection, there is another way, but you have to use interfaces.

                              Consider the following code:

                              Code:
                              <bean id="singletonA" class="SingletonA">
                                <param property="name" value="hello" />
                              </bean>
                              
                              <!-- notice the bean id is called prototypeB1, you can have multiple like this -->
                              <!-- prototypeBImpl implements PrototypeB interface -->
                              <bean id="prototypeB1" class="PrototypeBImpl" scope="prototype">
                                <param property="objectA" ref="singletonA" />
                              </bean>
                              Now, if i understand you correctly, whenever prototypeB is instantiated, it must have reference to singletonA.

                              You can create the prototypeB in the following manner using ServiceLocatorFactoryBean.

                              First, create a ServiceLocatorFactoryBean:

                              Code:
                              <bean id="factoryB" class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
                                <property name="serviceLocatorInterface" value="package.FactoryB"
                              </bean>
                              Two, create an interface:

                              Code:
                              public interface FactoryB {
                                //Returns interface PrototypeB
                                public PrototypeB getPrototypeB();
                              }
                              Three, Create PrototypeB interface:

                              Code:
                              public interface PrototypeB {
                                // methods
                                public SingletonA getA();
                              }
                              Finally, the concrete class:

                              Code:
                              public class PrototypeBImpl implements PrototypeB {
                                //...
                              }
                              
                              //Client code: Dependency-inject the factory:
                              
                              public ClientForB {
                                private FactoryB factoryB;
                               
                                public void someMethod() {
                                  //Will return a NEW instance of prototypeB, for every call,  with "singletonA" already set!
                                  prototypeB = factoryB.getPrototypeB();
                                  prototypeB.setAdditionalValues(); //Any additional values apart from objectA
                                  log.debug(prototypeB.getA().getName());
                                }
                              }
                              The advantage of above approach is you are using interfaces for your objects/implementations, and you dont have to use method-lookup injection (which needs cglib) and you dont have to use ApplicationAware stuff. Additionally, you can force your client not to do a new PrototypeB(); instead get the client to instantiate via the factory.

                              As long as the whole app is running within the same spring context, you can get it working.

                              hint: You can also use a parameter to pass to the getPrototypeB() method in the interface and create objects based on the parameter.

                              Comment

                              Working...
                              X