Google

Nov 28, 2011

Spring Interview Questions and Answers : Spring Bean life cycle, DI, and IOC

Spring Interview Questions and Answers Q1 - Q14 are FAQs

Q1 - Q4 Overview & DIP Q5 - Q8 DI & IoC Q9 - Q10 Bean Scopes Q11 Packages Q12 Principle OCP Q14 AOP and interceptors
Q15 - Q16 Hibernate & Transaction Manager Q17 - Q20 Hibernate & JNDI Q21 - Q22 read properties Q23 - Q24 JMS & JNDI Q25 JDBC Q26 Spring MVC Q27 - Spring MVC Resolvers

Q5. Can you describe the bean life cycle?
A5. A Spring Bean represents a POJO (Plain Old Java Object) performing useful operation(s). All Spring Beans reside within a Spring IOC Container. The Spring Framework hides most of the complex infrastructure and the communication that happens between the Spring Container and the Spring Beans. The state-chart diagram below highlights these communications.


Q6. What is a BeanFactory?
A6. The BeanFactory is the actual container which instantiates, configures, and manages a number of beans. These beans typically collaborate with one another, and thus have dependencies between themselves.

Q. How would you go about wiring up the spring managed bean dependencies?
A. In general, the dependencies are wired via the Spring config file. For example, the MyBeanService depends on MyBeanDao, and MyBean depends on MyBeanService, etc via either constructor or setter injection.

Here is the big picture of the collaborating classes and interfaces.


Here are the libraries ( highlighted in blue rectangle) that needs to be in the classpath.The commons-logging is used by the spring-beans-xx.jar.



STEP 1: Firstly define the relevant interfaces. Coding to interfaces is a good design parctice that loosely couples your classes.


package test;

public interface MyBeanDao {
   abstract void daoMethod();
}

package test;

public interface MyBeanService {
    abstract void serviceMethod();
}

Now, define the concrete implementation for the above interfaces.

package test;

public class MyBeanDaoImpl implements MyBeanDao {

    @Override
    public void daoMethod() {
        System.out.println("dao method invoked ...");
    }
}

package test;

public class MyBeanServiceImpl implements MyBeanService {
    
    private MyBeanDao beanDao;

    @Override
    public void serviceMethod() {
       System.out.println("Service method invoked...");
       beanDao.daoMethod();
    }
    
    public void setBeanDao(MyBeanDao beanDao) {
        System.out.println("setter injection .....");
        this.beanDao = beanDao;
    }  
}
 

Next, define the MyBean class that makes use of the MyBeanService and the

package test;

public class MyBean {
    
    private MyBeanService beanService;
    
    public MyBean(MyBeanService beanService) {
        System.out.println("Constructor injection...");
        this.beanService = beanService;
    }
    
    public void testMethod(){
        System.out.println("My bean method invoked ....");
        beanService.serviceMethod();
    }
}

STEP 2: Wire up the beans and the dependencies via an IOC container like Spring. The beans.xml file is shown below.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" 
 xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
     http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

 <bean id="myBeanDao" class="test.MyBeanDaoImpl"/>
 
 <bean id="myBeanService" class="test.MyBeanServiceImpl">
    <!-- setter injection of dao into service -->
    <property name="beanDao" ref="myBeanDao" />
 </bean>
 
 <bean id="myBean" class="test.MyBean"> 
    <!-- constructor injection of service into mybean -->
    <constructor-arg><ref bean="myBeanService" /></constructor-arg>
 </bean>
 
</beans>

As you can see, the MyBeanDao is injected via the setter injection into MyBeanService, and the MyBeanService is injected into MyBean via the constructor injection.


Q. How do you bootstrap the initial bean?
A.

STEP 3: The TestSpring class is the client class that makes use of the MyBean. In order to access the initial entry point into your application, which in this case is "MyBean", it needs to be bootstrapped via a BeanFactory implementation class. It can be done a number of ways as demonstrated below.


Using the "ClassPathXmlApplicationContext"

package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring {
    
    public static void main(String[] args) {
        ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] {"test/beans.xml"});
        BeanFactory factory = (BeanFactory) appContext;
        MyBean bean = (MyBean)factory.getBean("myBean"); 
        bean.testMethod();  
    }   
}



Using the "FileSystemResource"

package test;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

public class TestSpring {
    
    public static void main(String[] args) {
        Resource res = new FileSystemResource("bin/test/beans.xml");
        XmlBeanFactory factory = new XmlBeanFactory(res);
        MyBean bean = (MyBean)factory.getBean("myBean"); 
        bean.testMethod();  
    }   
}


Using the "ClassPathResource"

package test;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class TestSpring {
    
    public static void main(String[] args) {
        ClassPathResource res = new ClassPathResource("test/beans.xml");
        XmlBeanFactory factory = new XmlBeanFactory(res);
        MyBean bean = (MyBean)factory.getBean("myBean"); 
        bean.testMethod();  
    }   
}

STEP 4: Run the TestSpring as a stand alone application, which prints the following.

setter injection .....
Constructor injection...
My bean method invoked ....
Service method invoked...
dao method invoked ...

When MyBean bean = (MyBean)factory.getBean("myBean"); is executed, the dependent beans are created and wired up by the IOC container. You can further extend this by providing the necessary hooks to further enhance your understanding.

Q7. What would you do if it’s not practical (or impossible) to wire up your entire application into the Spring framework, but you still need a Spring loaded bean in order to perform a task?

A7. For example,
  • an auto generated web service client class! But you do want to use the dependency injection feature of Spring to get some of the other beans injected in to this class.
  • A legacy code that needs to make use of a Spring bean.

The ApplicationContextAware interface provided by Spring allows you to wire some java classes which are unable (or you don’t want it) to be wired to the Spring application context.


STEP 1: The ApplicationContextAware interface makes sense when an object requires access to a set of collaborating beans.


package test;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class MyServiceFactory implements ApplicationContextAware {
    
    private ApplicationContext context;

    public void testMethod2(){
        System.out.println("Test method2 invoked ....");
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx)
            throws BeansException {
       System.out.println("setting application context ..."); 
       this.context = ctx;
    }
    
    
    public MyBeanService getInstance(String accessCode) {
        //.....some logic
        MyBeanService beanService = (MyBeanService) context.getBean("myBeanService");
        return beanService;
    }
}


STEP 2: The beans2.xml file. The MyServiceFactory is not wired up.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" 
 xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
     http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">
 
 
 <bean id="myBeanDao" class="test.MyBeanDaoImpl"/>
 
 <bean id="myBeanService" class="test.MyBeanServiceImpl">
    <!-- setter injection of dao into service -->
    <property name="beanDao" ref="myBeanDao" />
 </bean>
 
 <!-- No DI wiring -->
 <bean id="myServiceFactory" class="test.MyServiceFactory" /> 
   
</beans>


STEP 3: Finally, the client code that makes use of the MyServiceFactory class.

package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring2 {
    
    public static void main(String[] args) {
        ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] {"test/beans2.xml"});
        BeanFactory factory = (BeanFactory) appContext;
        MyServiceFactory servicefactory = (MyServiceFactory)factory.getBean("myServiceFactory"); 
        MyBeanService service = servicefactory.getInstance("111");
        service.serviceMethod();
    }   
}

The output will be:

29/11/2011 3:59:29 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@145e044: startup date [Tue Nov 29 15:59:29 EST 2011]; root of context hierarchy
29/11/2011 3:59:29 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [test/beans2.xml]
29/11/2011 3:59:29 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1a42792: defining beans [myBeanDao,myBeanService,myServiceFactory]; root of factory hierarchy
setter injection .....
setting application context ...
Service method invoked...
dao method invoked ...



Q8. How would you create an application context from a web application?
A8. As opposed to the BeanFactory, which will often be created programmatically, ApplicationContexts can be created declaratively using a ContextLoader. You can register an ApplicationContext using the ContextLoaderListener as shown below in the web.xml file. The Spring context listener provides more flexibility in terms of how an application is wired together. It uses the application's Spring configuration to determine what object to instantiate and loads the objects into the application context used by the servlet container.

<web-app>
  .....
  <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  ....
</web-app> 

By default, it looks for a file named applicationContext.xml file in WEB-INF folder. But, you can configure the org.springframework.web.context.ContextLoaderListener class to use a context parameter called contextConfigLocation to determine the location of the Spring configuration file. The context parameter is configured using the context-parameter element. The context-param element has two children that specify parameters and their values. The param-name element specifies the parameter's name. The param-value element specifies the parameter's value.

<web-app>
  ...
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/beans.xml</param-value>
  </context-param>

  <listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  ...
</web-app>

Note: There will be only one ServletContext for each web application. ServletContext will be created while deploying the application. Once the ServletContext is created, it will be used by all the servlets and jsp files in the same application. ServletContext is also called as the application scope variables in the web application scenario. The ContextLoaderListener is in the spring-web-xxx.jar. It is quite handy to check the Spring API for org.springframework.web.context.support.XmlWebApplicationContext class that describes this.

For a WebApplicationContext that reads in a different bean definition format, you could define your own implementation, and define your implementation with the "contextClass" init parameter.

Here is another example with multiple Spring files.

<webapp>
   ..
   <context-param>
  <param-name>contextClass</param-name>
  <param-value>com.myapp.MyappXmlWebApplicationContext</param-value>
 </context-param>

   <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   classpath*:/com/myapp/transactionContext.xml
   classpath*:/com/myapp/daoContext.xml  
   classpath*:/com/myapp/override-daoContext${my.env}.xml
            /WEB-INF/webservice-interceptor-config.xml
   /WEB-INF/webservice-config.xml
   classpath*:/cxf.xml
  </param-value>
 </context-param>   
 
   <listener> 
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>
   
</web-app>


The contextClass can be defined something like.

package com.myapp;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.web.context.support.ServletContextResourcePatternResolver;
import org.springframework.web.context.support.XmlWebApplicationContext;

public class MyappXmlWebApplicationContext extends XmlWebApplicationContext {
    private static final String MY_ENV = "my.env";
    private static final String MY_ENV_PLACEHOLDER = "\\$\\{" + MY_ENV + "\\}";

    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PatchedResourcePatternResolver(this);
    }

    private static class PatchedResourcePatternResolver extends ServletContextResourcePatternResolver {

        public PatchedResourcePatternResolver(ResourceLoader resourceLoader) {
            super(resourceLoader);
        }

        public Resource[] getResources(String locationPattern) throws IOException {
            locationPattern = locationPattern.replaceAll(MY_ENV_PLACEHOLDER, System.getProperty(MY_ENV, ""));
            Resource[] resources = super.getResources(locationPattern);

            if (0 < locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()).length()) {
                return resources;
            }

            Collection<Resource> filteredResources = new ArrayList<Resource>();
            for (int i = 0; i < resources.length; i++) {
                Resource resource = resources[i];
                if (!resource.getURL().getProtocol().equals("jar")) {
                    filteredResources.add(resource);
                }
            }
            return (Resource[]) filteredResources.toArray(new Resource[filteredResources.size()]);
        }
    }
}


More Spring Interview Questions and Answers

Labels:

7 Comments:

Anonymous Help Desk said...

Great stuff! I really appreciate your efforts in bringing out some important questions on Java interview process. It is very important to learn these tips before proceeding to the interview.

2:17 AM, November 29, 2011  
Blogger jaylen watkins said...

I appreciate you for taking time to post such a informative article about Interview Questions on Java interview process. Well done.

11:21 PM, November 29, 2011  
Anonymous Javin @ Struts interview questions said...

Nice questions mate and to the point answers thanks. here are some from my collection of Spring interview questions answers you may like

1:03 AM, December 05, 2011  
Anonymous Anonymous said...

really great work dude...

7:09 PM, September 03, 2012  
Anonymous Anonymous said...

Really helpful notes... Thanks ! ! !

10:11 PM, January 11, 2014  
Blogger bhaskar_bhardwaj said...

Great Stuff !!

8:56 PM, September 01, 2014  
Anonymous Anonymous said...

servicefactory.getInstance("111"); means

9:33 PM, September 10, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home