How to avoid using ApplicationContext.getBean() when implementing Spring IOC

46,940

Solution 1

The simple answers are yes and no, no, and no. And finally, do a search online for spring MVC, as this probably does what you want.

So, your approach. Yes, you've got most of it right. However, it's considered very bad practice to use static methods for everything. And, you don't need to. Spring is based on the idea that you can simply create normal pojos, and spring will use them as singletons, and inject them into one another (it can also create objects on the fly, but I'm going for the common case here). If you use static classes and methods then:

  • You can't mock them for unit testing (you're using JUnit right?)
  • You can't use them with inheritance
  • Static initialisers are a great way to loose exceptions
  • etc, etc

So, yes to injection, and no to static stuff.

Next, performance. You're right in that it's a lot slower to use spring, but, if you do all your injection on startup it only happens once. Spring is meant for server side applications where there is likely to be a number of singleton classes passing data around. So, there might be a class to get stuff from a DB, one to process it, and one to display it, and spring is used to wire them together.

If you're using spring in an application where you start up repeatedly, like a command line app, then you are using it for the wrong sort of application, and you probably want to use a builder or something. Spring is meant for big enterprise apps that aren't restarted often.

Finally, if you simply inject all the dependencies for a class into it at startup, and you do this with all your classes, then you don't need to do any getBean stuff at all. Also, using the init-method and destroy-method attributes on a bean means that you can start up processes once spring has finished injecting dependencies. You need only load the context, and your app will spring (pun intended) into existence.

As for web projects, Spring MVC basically takes the whole inversion of control pattern and applies it to web applications. The spring stuff gets loaded by the container, and you can define the URLs to respond to using nothing more than bean names. And most of your code can stay as pojos. If you have something insanely complex, you may want to look at spring web flow, but I'd advise you to make sure that your spring foo is very strong before attempting that.

Solution 2

Here's my example for getting the first instance without actually calling getBean() on ApplicationContext.

public class Test{
  // Declare private static variable so that we can access it in main()
  private static Triangle triangle;

  // Use constructor injection to set the triangle
  public Test(Triangle triangle) {
      Test.triangle = triangle;
  }

  public static void main(String[] args) {
      // Specify the context file containing the bean definitions
      // Spring automatically creates instances of all the beans defined
      // in this XML file. This process is performed before you actually make
      // a getBean("beanName") call.
      ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

      // Use instance methods of triangle 
      Test.triangle.draw();
  }
} 

You can use another way:

In spring.xml (Your bean configuration XML file)

<bean class="com.example.Test" init-method="myMethod">
    <constructor-args ref="triangle"/>
</bean>

Now for your main class

public class Test {
  private final Triangle triangle;

  public Test (Triangle triangle) {
     this.triangle = triangle;
  }

  public static void main (String[] args) {
     ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  }

  // Called by Spring immediately after the Triangle Bean has been created and
  // all the properties for the bean have been set. This method name must match
  // the one specified with destroy-method attribute in spring.xml
  public void myMethod () {
     triangle.draw();
  }
}
Share:
46,940
srk
Author by

srk

A self exploratory human, self-taught programmer, with a constant thirst for learning.

Updated on August 12, 2020

Comments

  • srk
    srk almost 4 years

    I'm just getting started with Spring IOC concept. I often see most of the examples found in the internet use the code to get the object.

    ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    Hello hello = (Hello) appContext.getBean("hello"); 
    

    As a reference from these questions 1 and 2 in the stackoverflow. I've inferred that, it's not necessary to use appContext.getBean("hello") in the code which is considered to be the bad practice. Also, not recommended anymore. Correct me right here, If my inference is wrong.

    Keeping that in view, I have made changes in my project accordingly. Here's my applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    <bean id="utilClassRef" class="org.hd.derbyops.DUtils" lazy-init="false" />
    <bean id="appContext" class="org.hd.derbyops.ContextProvider" lazy-init="false">
       <property name="utils" ref="utilClassRef" />
    </bean>
    </beans>
    

    My contextProvider Class Code

    public class ContextProvider implements ApplicationContextAware {
    
        private static ApplicationContext ctx;
    
        /**
         * Objects as properties
         */
        private static DUtils utils;
    
        public void setApplicationContext(ApplicationContext appContext)
                throws BeansException {
            ctx = appContext;
    
        }
    
        public static ApplicationContext getApplicationContext() {
            return ctx;
        }
    
        public static DUtils getUtils() {
            return utils;
        }
    
        public void setUtils(DUtils dUtilsRef) {
            utils = dUtilsRef;
        }
    
    }
    

    For instance, consider a class A that depends on org.hd.derbyops.DUtils. I'm using the following code line

    ContextProvider.getUtils();
    

    inorder to get DUtils Object in class A, thus avoiding usage of ApplicationContext.getBean() anywhere in my code.

    Assume, if I have 10 classes and my class A is dependent on all of them, whose objects to be created and accessed without using ApplicationContext.getBean(). In that case also, as done above, I have a thought of creating properties of ContextProvider class followed by setter's and getter's of that property, where in get<PropertyName> is static. So that, I can use it wherever I'm in need of an object, like this

    ContextProvider.get<PropertyName>;
    

    Here's my brief question. Firstly, Is my approach right? If it's right, loading all the beans at the start-up, wouldn't it be a performance killer? How would you do that in your applications without calling getBean atleast more than once?

    If you were to design a web-application & you were to implement Spring IOC, without using ApplicationContext.getBean() in any of the code. How would you do that?

    Note: with reference to the other questions tagged above

    Calling ApplicationContext.getBean() is not Inversion of Control!

  • Kraken
    Kraken about 10 years
    In mycompany, I've never seen ApplicationContext.getBean() and stuff. But that's becuase these are enterprise level web applications. So what exactly loads up all my classes for me? Is it the server that does it?
  • Jimadilo
    Jimadilo about 10 years
    Normally you use one of the pre-canned Spring application loading classes, which are standard JEE components like servlets and whatnot. These then kick off all the spring IOC stuff. Tucked away in the bowels of those classes, there'll be a call to create the application context from the XML file, associate it with the currently running application, and make the application context available in some way.