struts2与spring的整合中有一种方法是通过struts-spring-plugin,使用该插件指定struts中的objectfactory为spring的beanfactory,简单的说,就是使用spring 的bean容器管理struts的Action的实例化。
使用步骤:
1.引入struts2-spring-plugin-x-x-x.jar 到classpath
2.在struts.xml或者struts2.properties中指定objectFactory
<struts>
<constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory" />
...
</struts>
事实上这个步骤可以省略,在struts2-spring-plugin-x-x-x.jar 有一个struts-plugins.xml,格式与struts.xml的格式一致,struts的配置文件加载顺序,显示struts-default.xml,定义在struts-core.jar中。然后加载struts.xml,最后加载struts-plugin.xml。
3.在Action的就可以使用@Autowired之类的Annotation注入Bean,如
@Component
public class PandoraAction {
@Inject
private TestService testService;
探究其原理,自然需要从StrutsSpringObjectFactory类开始了。
public class StrutsSpringObjectFactory extends SpringObjectFactory implements ObjectFactoryInitializable {
private static final Log log = LogFactory.getLog(StrutsSpringObjectFactory.class);
/* (non-Javadoc)
* @see org.apache.struts2.util.ObjectFactoryInitializable#init(javax.servlet.ServletContext)
*/
public void init(ServletContext servletContext) {
log.info("Initializing Struts-Spring integration");
ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
if (appContext == null) {
// uh oh! looks like the lifecycle listener wasn't installed. Let's inform the user
String message = "********** FATAL ERROR STARTING UP SPRING-STRUTS INTEGRATION **********\n" +
"Looks like the Spring listener was not configured for your web app! \n" +
"Nothing will work until WebApplicationContextUtils returns a valid ApplicationContext.\n" +
"You might need to add the following to web.xml: \n" +
" <listener>\n" +
" <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n" +
" </listener>";
log.fatal(message);
return;
}
this.setApplicationContext(appContext);
StrutsSpringObjectFactory继承自SpringObjectFactory类,在初始化时从ServletContext取到ApplicationContext。
SpringObjectFactory 继承自com.opensymphony.xwork2.ObjectFactory,ObjectFactory提供Action的默认实例话功能。
public class SpringObjectFactory extends ObjectFactory implements ApplicationContextAware
/**
* Looks up beans using Spring's application context before falling back to
* the method defined in the {@link ObjectFactory}.
*
* @param beanName
* The name of the bean to look up in the application context
* @return A bean from Spring or the result of calling the overridden
* method.
* @throws Exception
*/
public Object buildBean(String beanName) throws Exception {
try {
return appContext.getBean(beanName);
} catch (NoSuchBeanDefinitionException e) {
Class beanClazz = getClassInstance(beanName);
return buildBean(beanClazz);
}
}
/**
* @param clazz
* @throws Exception
*/
public Object buildBean(Class clazz) throws Exception {
Object bean = null;
try {
bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
} catch (UnsatisfiedDependencyException e) {
// Fall back
bean = super.buildBean(clazz);
}
bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());
// We don't need to call the init-method since one won't be registered.
bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());
return autoWireBean(bean);
}
appContext就是在初始化中setApplicationContext注入进去的。
通过重载struts2中默认的buildBean方法,通过spring的bean容器实例化action bean。
参考资料:
1.Struts中其实也有一些IOC的概念,看看他的bean的配置:
http://struts.apache.org/2.0.14/docs/bean-configuration.html
2.struts-spring-plugin的介绍:
http://struts.apache.org/2.x/docs/spring-plugin.html
3.struts-spring-plugin关键类 StrutsSpringObjectFactory (继承自SpringObjectFactory),SpringObjectFactory(继承自ObjectFactory)的关键代码:
http://www.koders.com/java/fid5C3A785273DB48FACE6A555235E29EB629F18284.aspx
http://www.koders.com/java/fid8FB58F1A37336CC84161E3A655F9D4F73A36EC6F.aspx