Google

Feb 19, 2014

Spring lookup-method injection to inject prototype scoped bean into a singleton bean

This post extends Tutorial to understand Spring scopes -- singleton Vs prototype.

Step 0: You need asm and cgilib libraries in addition to Spring libraries.



Step 1: define the Dao (Data Access Object) interface.


package com.mycompany.understanding.spring;

public interface MyDao {
 abstract void printData();
}

Step 2: Define the Dao implementation.

package com.mycompany.understanding.spring;

public class MyDaoImpl implements MyDao {

 @Override
 public void printData() {
  System.out.println("printing data"); 
  System.out.println(this);
 }
}


Step 3: Define the service interface.

package com.mycompany.understanding.spring;

public interface MyService {
 abstract void performTask();
}

Step 4: Define the service implementation. Note that the class is abstract as Spring will decorate this class with cgilib.

package com.mycompany.understanding.spring;

public abstract class MyServiceImpl implements MyService {

 protected abstract MyDao createMyDao();

 @Override
 public void performTask() {
  System.out.println("Performing tasks .............");
  createMyDao().printData();
 }
}

Step 5: The spring context file applicationContext.xml that wires up dao and service. Take note of the "lookup-method".

<?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.0.xsd">

    <bean id="myDaoDef" class="com.mycompany.understanding.spring.MyDaoImpl" scope="prototype"/>
    
    <bean id="myServiceDef" class="com.mycompany.understanding.spring.MyServiceImpl" scope="singleton"> 
       <lookup-method name="createMyDao" bean="myDaoDef" /> 
    </bean>

</beans>

Step 6: Executable main class.

package com.mycompany.understanding.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyMainApp {
 
 public static void main(String[] args) {
  ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
  for (int i = 0; i <3; i++) {
   MyService service = (MyService) applicationContext.getBean("myServiceDef");
   System.out.println(service);
   service.performTask();
  }
 }
}

Output if you run the above class

com.mycompany.understanding.spring.MyServiceImpl$$EnhancerByCGLIB$$35dfd4bb@750efc01
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@2ac2e1b1
com.mycompany.understanding.spring.MyServiceImpl$$EnhancerByCGLIB$$35dfd4bb@750efc01
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@606f4165
com.mycompany.understanding.spring.MyServiceImpl$$EnhancerByCGLIB$$35dfd4bb@750efc01
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@282e7f59


Single instance of service has 3 separate instances of  Dao.

Labels: ,

Feb 17, 2014

Tutorial: Understanding Spring scopes -- Singleton Vs Prototype

This posts extends Understanding Spring scopes -- Singleton Vs Prototype.

Step 0: Spring Jar files required. You can use maven or download and add to the classpath.



Step 1: Define the Java interface for Dao class.


package com.mycompany.understanding.spring;

public interface MyDao {
 abstract void printData();
}


Step 2: Define the Dao implementation.

package com.mycompany.understanding.spring;

public class MyDaoImpl implements MyDao {

 @Override
 public void printData() {
  System.out.println("printing data"); 
  System.out.println(this);
 }

}

Step 3: Define the Service interface.

package com.mycompany.understanding.spring;

public interface MyService {
 abstract void performTask();
}

Step 4:  Define the Service implementation into which the Dao implementation gets injected.

package com.mycompany.understanding.spring;

public class MyServiceImpl implements MyService {

 private MyDao myDao;
 
 public MyServiceImpl(MyDao myDao) {
  this.myDao = myDao;
 }

 @Override
 public void performTask() {
  System.out.println("Performing tasks .............");
  myDao.printData();
 }
}






Step 5: Use Spring context file  applicationContext.xml to wire up the dependencies. Note that both beans are defined as singleton, which is the default.

<?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.0.xsd">

    <bean id="myDaoDef" class="com.mycompany.understanding.spring.MyDaoImpl" scope="singleton"/>
    
    <bean id="myServiceDef" class="com.mycompany.understanding.spring.MyServiceImpl" scope="singleton"> 
       <constructor-arg name="myDao" ref="myDaoDef" /> 
    </bean>

</beans>


Step 6:  The runnable main class. The applicationContext.xml is bootstrapped here.

package com.mycompany.understanding.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyMainApp {
 
 public static void main(String[] args) {
  ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
  for (int i = 0; i <3; i++) {
   MyService service = (MyService) applicationContext.getBean("myServiceDef");
   System.out.println(service);
   service.performTask();
  }
 }
}

Step 7: Running the main class and comparing the results with different scopes. The for loop was created to instantiate more than one bean. Look at the memory address of the beans printed to see how many instances are created.

1.When both beans are singleton:

com.mycompany.understanding.spring.MyServiceImpl@7188eb7
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@5d419404
com.mycompany.understanding.spring.MyServiceImpl@7188eb7
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@5d419404
com.mycompany.understanding.spring.MyServiceImpl@7188eb7
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@5d419404

Only MyDaoImpl@5d419404 and MyServiceImpl@7188eb7 are created.

2. When both beans are prototypes: now change both scopes to "prototype" in the applicationContext.xml and retrun.

<?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.0.xsd">

    <bean id="myDaoDef" class="com.mycompany.understanding.spring.MyDaoImpl" scope="prototype"/>
    
    <bean id="myServiceDef" class="com.mycompany.understanding.spring.MyServiceImpl" scope="prototype"> 
       <constructor-arg name="myDao" ref="myDaoDef" /> 
    </bean>

</beans>


You can see 3 instances of service and 3 instances of Dao are created.

com.mycompany.understanding.spring.MyServiceImpl@64c53235
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@4e636942
com.mycompany.understanding.spring.MyServiceImpl@8dc488c
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@361ee3df
com.mycompany.understanding.spring.MyServiceImpl@2602613b
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@663d7bfb


3. When Service bean is singleton and Dao bean is prototype

com.mycompany.understanding.spring.MyServiceImpl@7188eb7
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@5d419404
com.mycompany.understanding.spring.MyServiceImpl@7188eb7
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@5d419404
com.mycompany.understanding.spring.MyServiceImpl@7188eb7
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@5d419404


You can only see 1 instance of service bean and 1 instance of prototype bean. This is not desired as in some scenarios you want to create new prototype bean again and again. This is where lookup-method comes in handy.

4. When Service bean is prototype and Dao bean is singleton.

com.mycompany.understanding.spring.MyServiceImpl@5d419404
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@7c5cc270
com.mycompany.understanding.spring.MyServiceImpl@528f1577
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@7c5cc270
com.mycompany.understanding.spring.MyServiceImpl@2fca61f9
Performing tasks .............
printing data
com.mycompany.understanding.spring.MyDaoImpl@7c5cc270


You can see 3 instances of the service beans and only 1 instance of the dao bean. Simple examples like this can clarify the concepts.

Scenario 3 is not desired as in some scenarios, and you want to create new prototype bean again and again. This is where lookup-method comes in handy. I will cover this in the next post.

Labels: ,

Feb 13, 2014

Understanding Spring scopes -- Singleton Vs Prototype

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

You will be hard pressed to find a Java project that does not use Spring, hence it pays to know its fundamentals. These questions and answers on Spring scopes are often asked in good job interviews.

Q. Does Spring dependency injection happen during compile time or runtime?
A. Runtime during creating an object.

Q9. What is the difference between prototype scope and singleton scope? Which one is the default?
A9. Singleton means single bean instance per IoC container, and prototype means any number of object instances per IoC container. The default scope is "singleton".

Q. When will you use singleton scope? When will you use prototype scope?
A. Singleton scope is used for stateless object use. For example, injectiong a DAO (i.e. Data Access Object) into a service object. DAOs don't need to maintain conversation state. For example,


<?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.0.xsd">

    <bean id="myDaoDef" class="com.mycompany.understanding.spring.MyDaoImpl" scope="singleton"/>
    
    <bean id="myServiceDef" class="com.mycompany.understanding.spring.MyServiceImpl" scope="singleton"> 
       <constructor-arg name="myDao" ref="myDaoDef" /> 
    </bean>

</beans>


Prototype is useful when your objects maintain state in a multi-threaded environment. Each thread needs to use its own object and cannot share the single object. For example, you might hava a RESTFul web service client making multi-threaded calls to Web services. The REST easy client APIs like RESTEasy uses the Apache Connection manager which is not thread safe and each thread should use its own client. Hence, you need to use the prototype scope.

Q. Would both singleton and prototype bean's life cycle be managed by the Spring IoC container?
A. Yes and no. The singleton bean's complete life cycle will be managed by Spring IoC container, but with regards to prototype scope, IoC container only partially manages the life cycle - instantiates, configures, decorates and otherwise assembles a prototype object, hands it to the client and then has no further knowledge of that prototype instance. As per the spring documentation

"This means that while initialization lifecycle callback methods will be called on all objects regardless of scope, in the case of prototypes, any configured destruction lifecycle callbacks will not be called. It is the responsibility of the client code to clean up prototype scoped objects and release any expensive resources that the prototype bean(s) are holding onto."

Q. What happens if you inject a prototype scoped bean into a singleton scoped bean?
A. A new prototype scoped bean will be injected into a singleton scoped bean once at runtime, and the same prototype bean will be used by the singleton bean.

Q. What if you want the singleton scoped bean to be able to acquire a brand new instance of the prototype-scoped bean again and again at runtime?
A. In this  use-case, there is no use in just dependency injecting a prototype-scoped bean into your singleton bean, because as stated above, this only happens once when the Spring container is instantiating the singleton bean and resolving and injecting its dependencies. You can just inject a singleton (e.g. a factory) bean and then use Java class to instantiate (e.g with a newInstance(...) or create(..) method) a new bean again and again at runtime without relying on Spring or alternatively have a look at Spring's "method injection". As per Spring documentation for "Lookup method injection"




"Lookup method injection refers to the ability of the container to override methods on container managed beans, to return the result of looking up another named bean in the container. The lookup will typically be of a prototype bean as in the scenario described above. The Spring Framework implements this method injection by dynamically generating a subclass overriding the method, using bytecode generation via the CGLIB library."


Q10. What are the scopes defined in HTTP context?
A10. Following scopes are only valid in the context of a web-aware Spring ApplicationContext.

  • request Scope is for a single bean definition to the lifecycle of a single HTTP request.In other words each and every HTTP request will have its own instance of a bean created off the back of a single bean definition. 
  • session Scope is for a single bean definition to the lifecycle of a HTTP Session. 
  • global session Scope is for a  single bean definition to the lifecycle of a global HTTP Session. Typically only valid when used in a portlet context. 

Q. Does Spring allow you to define your own bean scopes?
A. Yes, from Spring 2.0 onwards you can define custom scopes. For example,
  • You can define a ThreadOrRequest and ThreadOrSession scopes to be able to switch between the environment you run in like JUnit for testing and Servlet container for running as a Web application. 
  • You can write a custom scope to inject stateful objects into singleton services or factories.
  • You can write a custom bean scope that would create new instances per each JMS message consumed
  • Oracle Coherence has implemented a datagrid scope for Spring beans. You will find many others like this.


In the next post, I will demonstrate "singleton" and prototype scopes with tutorial like code, Stay tuned.

Relevant tutorials:

Labels: ,