那时我有些不是很明白,为什么我的action类没有写注解@Component("xxAction"),还是可以被spring自动装配。那是因为action类被struts和struts2-spring-plugin创建,再由spring自动装配,但不由spring管理。如果我们想使用spring复杂的aop或spring其他的功能时,强烈建议将acion类注册到spring容器中。
今天,再次做测试,又有了出乎意料的结果。在此说明,我的测试中用的是annotion注解,不是xml文件。
之前,我们说过,当创建一个action类时,它会根据struts的配置文件的class属性的值与spring配置文件中的id属性的值相匹配。如果没有与之相匹配,将会像没有使用这个插件前一样创建,然后由spring自动装配。这两种情况会出现不同的结果。现在我们慢慢来说明。
假设我们有一个AddUserAction的类,位于com.action包下,它有属性userService:
package com.action;
import com.opensymphony.xwork2.ActionSupport;
import com.service.UserService;
public class AddUserAction extends ActionSupport {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
public String execute() throws Exception {
System.out.println(userService==null);
return SUCCESS;
}
}
以上这个类是我们最简单的action类,在没有引入struts2-spring-plugin.jar插件时,action类是由struts创建的,我们struts.xml文件是这样写的:
<struts>
<package name="registration" extends="struts-default">
<action name="addUser" class="com.action.AddUserAction">
<result>success.jsp</result>
</action>
</package>
</struts>
但如果我们引入struts2-spring-plugin.jar插件后,如果我们的struts.xml文件还是如同以上一样写,就会出现struts的配置文件的class属性的值与spring配置文件中的id属性的值不匹配,因为action类没有注册到spring的容器中。那action的创建由strutst和struts2-spring-plugin.jar插件创建,默认地根据名字到spring容器中去找相应的对象进行自动装配(不管你是否愿意,只要提供了set方法),所以userService不会是null值,这个action类的scope也默认的是prototype,但这个action类不在spring容器中。
自然的,以上这种情况不是我们想要的,因为很多情况都不在我们的控制范围内。那只要我们将action类的创建交给spring,就可以自主也配置我们想要的属性。这时我们将原来的action类改为:
package com.action;
mport javax.annotation.Resource;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.opensymphony.xwork2.ActionSupport;
import com.service.UserService;
@Component("addUserAction")
@Scope("prototype")
public class AddUserAction extends ActionSupport {
private UserService userService;
@Resource(name="userService")
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
public String execute() throws Exception {
System.out.println(userService==null);
return SUCCESS;
}
}
在第二个action类中,我们加入了相应的annotion,把我们的action类注册到spring容器中。我们的struts.xml文件也改为:
<struts>
<package name="registration" extends="struts-default">
<action name="addUser" class="addUserAction">
<result>success.jsp</result>
</action>
</package>
</struts>
这时,struts的配置文件的class属性的值与spring配置文件中的id属性的值匹配。如果我们不想装配userService,可以将@Resource(name="userService")删除。
所以,在struts.xml里的class的属性值决定你以那种方式创建action类,我个人倾向于将action类交给spring管理和自动装配。
如果有什么不正确的地方,欢迎大家指出。
====================================
Struts2与Spring的集成要用到Spring插件包struts2-spring-plugin-x-x-x.jar,这个包是同Struts2一起发布的。Spring插件是通过覆盖(override)Struts2的ObjectFactory来增强核心框架对象的创建。当创建一个对象的时候,它会用Struts2配置文件中的class属性去和Spring配置文件中的id属性进行关联,如果能找到,则由Spring创建,否则由Struts 2框架自身创建,然后由Spring来装配。Spring插件具体有如下几个作用:
— 允许Spring创建Action、Interceptror和Result。
— 由Struts创建的对象能够被Spring装配。
— 如果没有使用Spring ObjectFactory,提供了2个拦截器来自动装配action。
开发者不必在Spring中去注册action,尽管可以这么去做,通常Struts框架会自动地从action mapping中创建action对象
struts2-spring-plugin-x-x-x.jar插件中有一个struts-plugin.xml文件,该文件内容如下所示:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />
<!-- 设置Spring对象工厂为自动 -->
<constant name="struts.objectFactory" value="spring" />
<package name="spring-default">
<interceptors>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
</interceptors>
</package>
</struts>
其中设置了Struts 2框架常量struts.objectFactory的值为spring,实际上,spring是org.apache.struts2.spring.StrutsSpringObjectFactory类的缩写,默认情况下所有由Struts 2框架创建的对象都是由ObjectFactory实例化的,ObjectFactory提供了与其他IoC容器如Spring、Pico等集成的方法。覆盖这个ObjectFactory的类必须继承ObjectFactory类或者它的任何子类,并且要带有一个不带参数的构造方法。在这里用org.apache.struts2.spring.StrutsSpring ObjectFactory代替了默认的ObjectFactory。
如果Action不是使用Spring ObjectFactory创建的话,插件提供了两个拦截器来自动装配Action,默认情况下框架使用的自动装配策略是name,也就是说框架会去Spring中寻找与Action属性名字相同的bean,可选的装配策略还有:type、auto、constructor,开发者可以通过常量struts.objectFactory.spring.autoWire来进行设置。
Struts 2框架整合Spring后,处理用户请求的Action并不是Struts框架创建的,而是由Spring插件创建的。创建实例时,不是利用配置Action时指定的class属性值,根据bean的配置id属性,从Spring容器中获得相应的实例。