Spring 整合 Strusts2 - XinxinZhou/JavaEE GitHub Wiki
对于一个基于B/S架构的 JavaEE 应用而言,用户请求总是向MVC框架的控制器请求,而当控制器拦截到用户请求后,必须调用业务逻辑组件来处理用户请求。 那么,控制器改如何获取业务逻辑组件? 一、直接使用new关键字穿件业务逻辑组件,然后调用业务逻辑组件的方法,根据业务逻辑方法的返回值确定结果。但是这样会带来一些负面影响:
-
控制器直接创建业务逻辑组件,导致控制器与业务逻辑组件的耦合降低到代码层次,不利于高层次解耦。(代码属于低层次,配置文件高层次么?)
-
控制器不应该负责业务逻辑组件的创建,控制器只是业务逻辑组件的使用者,无须关系业务逻辑组件的实现。
-
每次创建新的业务逻辑组件导致性能下降。
二、所以我们可以采用工厂模式。 业务逻辑组件的生成通常应由工厂负责,而且工厂可以保证该组件的实例只需一个就够,避免重复实例化造成的系统开销。 采用工厂模式,将控制器与业务逻辑组件的实现分离,从而提供更好的解耦。在采用工厂模式的访问策略中,所有的业务逻辑组件的创建由工厂负责,业务逻辑组件的运行也应由工厂负责。而控制器只需定位工厂实例即可。
Spring框架就是一个大的工厂,负责业务逻辑组件的创建和生成,并可以管理业务逻辑组件的生命周期.(业务逻辑组件,持久层组件,控制器组件都可以).
How? (所以Action就是控制器) 控制器如何访问到Spring容器中的业务逻辑组件呢? 为了让Action访问到Spring的业务逻辑组件,有两种策略: Spring容器负责管理控制器Action,并利用依赖注入为控制器注入业务逻辑组件。 利用Spring的自动装配,Action将会自动从Spring容器中获取所需的业务逻辑组件。
8.6.3 让Spring管理控制器 让Spring来管理应用中的控制器,可以充分利用Spring的IoC特性,但需将配置Struts 2 的控制器部署在Spring容器中,导致配置文件冗余。
过程: Struts2的核心控制器首先拦截到用户请求,然后将请求转发给对应的Action处理,在此过程中,Struts2将负责创建Action实例,并调用其execute()方法,这个过程是固定的.
现在的情形: 我们已把Action实例交由Spring容器来管理,而不是由Struts2产生的。 那么,核心控制器如何知道调用Spring容器中的Action,而不是自行创建Action实例呢?
通过导入插件:struts2-spring-2.2.1.jar.
Spring插件提供一种伪Action,当我们在struts.xml文件中配置Action时,通常需要制定class属性,该属性就是用于创建Action实例的实现类。但Spring插件允许我们在指定class属性时(struts.xml中),不再指定Action的实际实现类,而是去指定Spring容器中的BeanID,这样Struts2就不再自己负责创建Action实例,而是通过Spring容器去获取Action对象。
So.关键: 当Struts2将请求转发给指定的Action时,Struts2中的该Action只是一个傀儡,只有一个代号(Bean ID), 并没有指定实际的实现类,当然也不可能创建Action实例,而隐藏在该Action下的是Spring容器中的Action实例---它才是真正处理用户请求的控制器。
Spring容器为控制器注入业务逻辑组件,这就是Spring和Struts2整合的关键所在。 当使用Spring容器管理 系统 的Action时,在Struts.xml文件中配置改Action时,class属性并不是指向该Action的实现类,而是指定了Spring容器中Action实例的ID.
-
struts.xml
-
<action name="loginPro" class="**loginAction**">
-
Spring:
-
<bean id="myService" class="org.xx.app.service.impl.MyServiceImpl"/>
-
<bean id="**loginAction**" class="org.xx.app.action.LoginAction" scope="prototype">
-
`<property name="ms" ref=""myService"/>`
-
</bean>
struts中为action配置时, 指定class的属性为loginAction名称,该名称对应于Spring容器中的一个Bean实例. Spring中注册bean实例 myService, 并将依赖(业务逻辑组件)注入loginAction Bean中。 ps: 当Spring管理Struts2的Action时,一定要配置scope属性,因为Action里包含了请求的状态信息,所以必须为每个请求对应一个Action,所以不能将该Action实例配置成单例模式.(prototype:每次返回一个新的实例. 单例:一直使用同一个实例)
这种策略充分利用了Spring的IoC特性,但也有一些不足:
- Spring管理Action,必须将所有的Action配置在Spring容器中,而struts.xml文件中也要配置一个"伪Action",从而导致配置文件冗余。
- Action的业务逻辑组件接受容器的注入,将导致代码的可读性降低。
8.6.4.使用自动装配 (xml配置方面简化而已) 基本一致,但在struts.xml中配置Action时,class需要指定为实际的action类.(与在不整合Spring时的配置文件一致) 在Spring容器中,只需要配置业务逻辑组件, bean id 要与action类中的组件命名一致. :自动装配与不整合spring的区别. 整合Spring框架与不整合时的区别不是在这个配置文件中体现,而是在创建该Action实例时体现出来。 如果不整合Spring框架,则Struts2框架负责创建Action实例,创建成功后就结束了; 如果整合Spring框架,则当Action实例创建完成之后,Spring插件还会负责为该Action注入所需的业务逻辑组件。 缺点: Action 与 业务逻辑组件的耦合降低了代码层次,必须在配置文件中配置Action所需控制器 同名 的业务逻辑组件。这不利于高层次的解耦.(对象名 == id: public MyService ms; bean id = "ms").
Action接受Spring容器的自动装配,代码可读性较差.