Tuesday, January 23, 2007

Spring: Prototype beans with Singletons - 2

The previous post described how to implement Lookup method injection and ServiceLocatorFactoryBean and BeanFactoryAware to enable singleton classes to use Prototype beans. This post will describe how to use Scoped beans (session or request or globalSession) from Spring managed beans in a Web application and also give the client servlet for testing the previous and the current examples.

Using in Web Applications

This is not for Singleton or Prototype beans. This solution is for using beans that are saved in the request of session scope. To implement this solution, you must inject an AOP proxy in place of the scoped bean, the proxy will then delegate the method call to the object that is in currently in the specified scope. All you have to do is to put the following in the bean definition
<aop:scoped-proxy/>
In the Web deployment descriptor (Shown in a following section), you will have to put a RequestContextListener in addition to the ContextLoaderListener. The RequestContextListener binds the HTTP request object to the Thread that is servicing that request. This makes beans that are request and session-scoped available further down the call chain (i.e. for spring managed beans invoked in the same thread of execution). For the Web Application scenario, I used a different Command bean shown below
package beans;

public class NewCommand {
private String someProperty;

public String getSomeProperty() {
return someProperty;
}

public void setSomeProperty(String someProperty) {
this.someProperty = someProperty;
}

public String execute() {
return "Command property : " + someProperty;
}
}
NewCommand.java

The Command Manager is shown below
package beans;

public class CmdMgrWeb {
private NewCommand command;

public Object process(String prop) {
command.setSomeProperty(prop);
return command.execute();
}

public NewCommand getCommand() {
return command;
}

public void setCommand(NewCommand command) {
this.command = command;
}
}
CmdMgrWeb.java

The Servlet

The following is the servlet used for testing the beans used here.
package servlets;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import beans.CmdMgrNoBFA;
import beans.CmdMgrServiceFactory;
import beans.CmdMgrWeb;
import beans.CommandManager;
import beans.NewCommand;

public class MethodInjectionServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
public MethodInjectionServlet() {
super();
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
request.getSession().setAttribute("command", new NewCommand());
BeanFactory factory = (BeanFactory) context;
PrintWriter writer = response.getWriter();

CommandManager commandManager = (CommandManager) factory.getBean("commandManager");
writer.println(commandManager.process("test"));

CmdMgrNoBFA cmdMgrNoBFA = (CmdMgrNoBFA) factory.getBean("cmdMgrNoBFA");
writer.println(cmdMgrNoBFA.process("test"));

CmdMgrServiceFactory cmdMgrServiceFactory = (CmdMgrServiceFactory) factory.getBean("cmdMgrServiceFactory");
writer.println(cmdMgrServiceFactory.process("test"));

CmdMgrWeb cmdMgrWeb = (CmdMgrWeb) factory.getBean("cmdMgrWeb");
writer.println(cmdMgrWeb.process("test"));

}

}
MethodInjectionServlet.java

The Web Deployment Descriptor

The web.xml file is shown below. You can see the two listeners required for using spring and the scoped beans.
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>MethodInjectionWeb</display-name>

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

<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<servlet>
<description></description>
<display-name>MethodInjectionServlet</display-name>
<servlet-name>MethodInjectionServlet</servlet-name>
<servlet-class>servlets.MethodInjectionServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>MethodInjectionServlet</servlet-name>
<url-pattern>/MethodInjectionServlet</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
WEB-INF/web.xml

The Bean Definitions

The following is the code for the applicationContext.xml file. It is quite self explanatory.
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<bean id="command" class="beans.Command" scope="prototype"></bean>

<!-- Basic implementation by extending BeanFactoryAware -->
<bean id="commandManager" class="beans.CommandManager"></bean>

<!-- The lookup-method is implemented by Spring -->
<bean id="cmdMgrNoBFA" class="beans.CmdMgrNoBFA">
<lookup-method name="createCommand" bean="command" />
</bean>

<!-- Use Service locator factory to obtain a reference -->
<bean id="springServiceFactory" class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value="beans.ServiceFactory" />
</bean>

<bean id="cmdMgrServiceFactory" class="beans.CmdMgrServiceFactory">
<property name="serviceFactory" ref="springServiceFactory"></property>
</bean>


<!-- Using in Web Applications -->
<bean id="newCommand" class="beans.NewCommand" scope="session">
<aop:scoped-proxy />
</bean>

<bean id="cmdMgrWeb" class="beans.CmdMgrWeb">
<property name="command" ref="newCommand" />
</bean>
</beans>
WEB-INF/applicationContext.xml

No comments:

Post a Comment