StrutsSpringObjectFactory继承了com.opensymphony.xwork2.spring.SpringObjectFactory,主要做了几件事情

来源:互联网 发布:数据库系统概论王珊ppt 编辑:程序博客网 时间:2024/06/04 18:49

之前一朋友问我strut2和spring集成时使用aop后造成注入失败:关于struts2-spring整合的问题,我就分析一下struts2如果和spring集成的,并解决这个问题。

 

此问题已经提交到struts2的JIRA,2.3.16将修复;https://issues.apache.org/jira/browse/WW-4110。

 

问题:

但是当我对action类加了spring-aop之后,写@resource不加getset方法的情况下又报错了,好像spring的注解又失效了,不知道这是为什么,请问您碰到过这种情况吗。

 

默认情况下,失败的情况只有两种:

当如<action name="myAction" class="cn.javass.MyAction">时,即没有交给spring管理:

1、 @Autowired   private Resource resource; 但无setter方法;

2、有setter方法,如setResource(),但无名字为resource的bean。

 

分析

首先介绍下struts2怎么去和spring集成的。

1、如果需要和spring集成,需要添加struts2-spring-plugin-***.jar,此处我们使用struts2-spring-plugin-2.3.1.1.jar;

 

2、接着struts2在启动时会按照如下顺序加载配置文件:

struts-default.xml 默认配置

struts-plugin.xml  插件配置(可以多个)

struts.xml 我们自己的

 

3、自动注册StrutsSpringObjectFactory为struts2的ObjectFactory,因此拿struts2的组件等都是问它要;

 

Java代码  收藏代码
  1. <bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />  
  2.   
  3. <!--  Make the Spring object factory the automatic default -->  
  4. <constant name="struts.objectFactory" value="spring" />  

 

4、 StrutsSpringObjectFactory继承了com.opensymphony.xwork2.spring.SpringObjectFactory,主要做了几件事情:

4.1、获取ApplicationContext:servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

4.2、获取自动装配的机制,可以在struts.xml配置常量:struts.objectFactory.spring.autoWire,默认是name;这个可以参考http://jinnianshilongnian.iteye.com/blog/1415461,3.3.3 自动装配;

 

5、接下来如果要获取如action,需要:

 

Java代码  收藏代码
  1. @Override  
  2. public Object buildBean(String beanName, Map<String, Object> extraContext, boolean injectInternal) throws Exception {  
  3.     Object o;  
  4.       
  5.     if (appContext.containsBean(beanName)) {  
  6.         o = appContext.getBean(beanName);  
  7.     } else {  
  8.         Class beanClazz = getClassInstance(beanName);  
  9.         o = buildBean(beanClazz, extraContext);  
  10.     }  
  11.     if (injectInternal) {  
  12.         injectInternalBeans(o);  
  13.     }  
  14.     return o;  
  15. }  

5.1、首先查找spring容器有木有,如果有直接返回;

 

5.2、否则调用buildBean(beanClazz, extraContext);创建新的bean;即<action name="myAction" class="cn.javass.MyAction"> class配置的不是beanName时;

 

6、buildBean(beanClazz, extraContext);

 

Java代码  收藏代码
  1. @Override  
  2. public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception {  
  3.     Object bean;  
  4.   
  5.     try {  
  6.         // Decide to follow autowire strategy or use the legacy approach which mixes injection strategies  
  7.         if (alwaysRespectAutowireStrategy) {  
  8.             // Leave the creation up to Spring  
  9.             bean = autoWiringFactory.createBean(clazz, autowireStrategy, false);  
  10.             injectApplicationContext(bean);  
  11.             return injectInternalBeans(bean);  
  12.         } else {  
  13.             bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);  
  14.             bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());  
  15.             // We don't need to call the init-method since one won't be registered.  
  16.             bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());  
  17.             return autoWireBean(bean, autoWiringFactory);  
  18.         }  
  19.     } catch (UnsatisfiedDependencyException e) {  
  20.         if (LOG.isErrorEnabled())  
  21.             LOG.error("Error building bean", e);  
  22.         // Fall back  
  23.         return autoWireBean(super.buildBean(clazz, extraContext), autoWiringFactory);  
  24.     }  
  25. }  

6.1、 如果是alwaysRespectAutowireStrategy,默认false,这个对于大家来说直接忽略,遗留策略,现在可以直接忽略。

6.2、正常情况会走到else中:

6.2.1、首先通过bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false)创建Bean;

6.2.2、执行Bean预处理:bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName()),此时可能发生@PostConstruct的初始化及一些Aware接口的注入;

6.2.2、执行Bean的后处理:bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName()),此时可能发生创建代理对象;

6.2.3、最后调用autoWireBean(bean, autoWiringFactory)装配对象,此时会调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory的populateBean完成,完成1、如果支持自动装配,会执行自动专配;2、如果有支持@Autowired注解,那么会调用InstantiationAwareBeanPostProcessor的postProcessPropertyValues;

 

如上的流程可以参考如下文章,有详细讲解:

Spring开闭原则的表现-BeanPostProcessor的扩展点-1

Spring开闭原则的表现-BeanPostProcessor扩展点-2 

 

 

 

但是getBean的流程是(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory):

 

1、InstantiationAwareBeanPostProcessor.applyBeanPostProcessorsBeforeInstantiation

2、InstantiationAwareBeanPostProcessor.applyBeanPostProcessorsAfterInitialization

如果此时有bean返回 直接返回;

3、doCreateBean

3.1、createBeanInstance

3.2、populateBean

3.2.1、InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation

3.2.2、autowire, for example AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE

3.2.3、InstantiationAwareBeanPostProcessor.postProcessPropertyValues

3.2.4、applyPropertyValues

 

4、initializeBean

4.1、invokeAwareMethods

4.2、BeanPostProcessor.postProcessBeforeInitialization

4.3、invokeInitMethods

4.4、BeanPostProcessor.postProcessAfterInitialization

 

所以综上,SpringObjectFactory的实现是存在问题的,我给了一个正确的方式:

Java代码  收藏代码
  1. //1、instantiation  
  2. bean = autoWiringFactory.createBean(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);  
  3.   
  4. //2、autowire  
  5. bean = autoWireBean(bean, autoWiringFactory);  
  6.   
  7. //3、initialization  
  8. bean = autoWiringFactory.initializeBean(bean, bean.getClass().getName());  

这才是正确的步骤。

 

如果按照struts2默认的实现,

bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());会执行创建代理,那么bean此时是代理对象;

 

那么接下来autoWireBean(bean, autoWiringFactory);会造成@Autowired   private Resource resource; 但无setter方法;注入失败。

 

到此分析完毕,已经提交struts2 jira:

https://issues.apache.org/jira/browse/WW-4110 

 

正确的SpringObjectFactory在附件中,请下载测试

  • test.rar (26.9 KB)
  • 下载次数: 43
阅读全文
0 0