Spring整合Struts2 之 深度解析

来源:互联网 发布:新歌2016网络红歌榜 编辑:程序博客网 时间:2024/06/05 00:39

一、启动Spring

  对于使用Spring的Web应用,无须手动创建Spring容器,而是通过配置文件声明式的创建Spring容器。在Web应用中创建Spring容器有如下两种方式:

  • 直接在web.xml文件中配置创建Spring容器
    • 利用ServletContextListener实现
    • 采用load-on-startup Servlet实现
  • 利用第三方MVC框架的扩展点,创建容器

1.1 在web.xml中利用ServletContextListener监听器

  这种方式最常见,为了让Spring容器随Web应用的启动而自动启动,借助于ServletContextListener监听器即可完成,该监听器可以在Web应用启动时回调自定义方法(该方法就可以启动Spring容器)。

  Spring提供了一个ContextLoaderListener,该监听器类实现了ServletContextListener接口。该类可以作为Listener使用,它会在创建时自动查找WEB-INF/下的applicationContext.xml文件。因此,如果只有一个配置文件,并且文件名为applicationContext.xml,则只需在web.xml文件中增加如下配置片段即可:

<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
  如果有多个配置文件需要载入,则需要使用<context-param.../>元素来确定配置文件的文件名。ContextLoaderListener加载时,会查找名为contextConfigLocation的初始化参数。因此,配置<context-param.../>时应制定参数名为contextConfigLocation。如下:

<!-- 指定多个配置文件 --><context-param><!-- 参数名为contextConfigLocation --><param-name>contextConfigLocation</param-name><!-- 多个配置文件之间以","隔开 --><param-value>WEB-INF/SpringConfig/*.xml,/WEB-INF/A.xml,/WEB-INF/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
注意:如果没有用contextConfigLocation制定配置文件,则Spring会自动查找WEB-INF/路径下的applicationContext.xml配置文件;如果有contextConfigLocation,则使用该参数确定的配置文件。如果无法找到合适的配置文件,Spring将无法正常初始化。
  Spring根据指定的配置文件创建WebApplicationContext对象,并将其保存在Web应用的ServletContext中。在大部分情况下,应用中的Bean无须感受到ApplicationContext的存在,只要利用ApplicationContext的IoC即可。如果需要在应用中获取ApplicationContext实例,则可以通过如下代码获取:

// 获取当前Web应用启动的Spring容器WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(ServletContex);
  当然也可以通过ServletContext的getAttribute方法获取ApplicationContext,但是用WebApplicationContextUtils类更方便。

1.2 采用load-on-startup Servlet机制

  1. load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法)
  2. 它的值必须是一个整数,表示servlet应该被载入的顺序。当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet
  3. 当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载
  4. 正数的值越小,该servlet的优先级越高,应用启动时就越先加载
  5. 当值相同时,容器就会自己选择顺序来加载
  6. <load-on-startup>x</load-on-startup>中x的取值1,2,3,4,5代表的是优先级,而非启动延迟时间。
<servlet>     <servlet-name>context</servlet-name>     <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>    <load-on-startup>1</load-on-startup></servlet> 
注意:这种方式,spring3.0以后不再支持,建议使用监听器方式。你可以查看一下spring3.0的change log ,里面注明: removed ContextLoaderServlet and Log4jConfigServlet

1.3 利用第三方MVC框架的扩展点

  Struts有一个扩展点PlugIn,spring正是利用了PlugIn这个扩展点,从而提供了与Struts的整合。spring提供了PlugIn的实现类org.springframework.web.struts.ContextLoadPlugIn,这个实现类可作为struts的PlugIn配置,Struts框架启动时,将自动创建Spring容器为了利用struts的PlugIn创建Spring容器,只需要在struts配置文件struts-config.xml中增加如下片段即可:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">      <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml,/WEB-INF/action-servlet.xml" />  </plug-in> 
  其中,指定contextConfigLocation属性值时,即可以指定一个spring配置文件的位置,可以指定多个spring配置文件的位置。

二、MVC框架与Spring整合

  对于一个基于B/S构架的Java EE应用而言,用户请求总是向MVC框架的控制器请求,而当控制器拦截到用户请求后,必须调用业务逻辑组件来处理用户请求。
  控制器应该如何获得业务逻辑组件?在实际开发中,很少采用new关键字来创建业务逻辑组件,然后调用业务逻辑组件的方法,原因如下:
  • 控制器直接创建业务逻辑组件,导致控制器和业务逻辑组件的耦合降低到代码层次,不利于高层次解耦
  • 控制器不应该负责业务逻辑组件的创建,控制器只是业务逻辑组件的使用者,无须关心业务逻辑组件的实现
  • 每次创建新的业务逻辑组件将导致性能下降
  实际开发中,通常采用工厂模式,或者服务定位器模式。对于采用服务定位器模式,是远程访问的场景,在这种场景下,业务逻辑组件已经在某个容器中运行,并对外提供某种服务。控制器无需理会该业务逻辑组件的创建,直接调用该服务即可,但在调用之前,必须先找到该服务——这就是服务定位器的概念。经典的JavaEE应用就是这种结构的应用。
  对于轻量级的JavaEE应用,工厂模式则是更实际的策略。因为在轻量级的JavaEE中,业务逻辑组件不是EJB,通常就是一个POJO,业务逻辑组件的生成通常应由工厂负责,而且工厂可以保证该组件的实例只需要一个就够了,可以避免重复实例化造成的系统开销。
  采用工厂模式,将控制器与业务逻辑组件的实现分离,从而提供更好的解耦。在采用工厂模式的访问策略中,所有的业务逻辑组件的创建由工厂负责,业务逻辑组件的运行也由工厂负责,而控制器只需要定位工厂实例即可,而采用Spring框架,则Spring称为最大的工厂。
为了让Action访问到Spring的业务逻辑组件,有两种策略:
  • Spring容器负责管理控制器Action,并利用依赖注入为控制器注入业务逻辑组件
  • 利用Spring的自动装配,Action将会自动从Spring容器中获取所需的业务逻辑组件

2.1 让Spring管理控制器

  Struts2的核心控制器首先拦截到用户请求,然后将请求转发给对应的Action处理,在此过程中,Struts2将负责创建Action实例,并调用其execute()方法。这个过程是固定的。现在的情形是:把Action实例交由Spring容器来管理,而不是由Struts2产生的,name核心控制器如何知道调用Spring容器中的Action,而不是自行创建Action实例呢?这个工作有Struts2提供的Spring插件(struts2-spring-plugin-*.jar)来完成。
  让Spring容器来管理应用中的控制器,可以充分利用Spring的IoC特性,但需要将配置Struts2的控制器部署在Spring容器中,因此导致配置文件冗余。Struts2提供的Spring插件提供了一种伪Action,在struts.xml文件中配置Action时,指定class属性时,不再指定Action的实际实际类,而是指定为Spring容器中的Bean ID,这样Struts2不再自己负责创建Action实例,而是直接通过Spring容器去获取Action对象。
代码示例详见:codes\08\8.7\spring-manage-action
注意:当Spring管理Struts2的Action时,一定要配置scope属性,因为Action里包含了请求的状态信息,必须为每个请求对应一个Action,所以不能将该Action实例配置成singleton行为,指定scope属性为prototype或request。
部署项目后,再启动过程中会有如下显示:
四月 05, 2017 2:50:18 下午 org.apache.struts2.spring.StrutsSpringObjectFactory info信息: Initializing Struts-Spring integration...四月 05, 2017 2:50:18 下午 com.opensymphony.xwork2.spring.SpringObjectFactory info信息: Setting autowire strategy to name四月 05, 2017 2:50:18 下午 org.apache.struts2.spring.StrutsSpringObjectFactory info信息: ... initialized Struts-Spring integration successfully
  很简单,Struts-Spring集成初始化——>指定自动装配策略为byname——>Struts-Spring集成初始化成功

2.2 使用自动装配

  在自动装配下,Action还是由Spring插件创建,Spring插件在创建Action实例时,利用Spring的自动装配策略,将对应的业务逻辑组件注入Action实例中。这种整合配置策略的配置文件简单,但控制器和业务逻辑组件耦合又提升到了代码层次,耦合较高。如果不指定自动装配,则系统默认使用byName自动装配,如上。
  所谓自动装配,即让Spring自动管理Bean与Bean之间的依赖关系,无须使用ref显式指定依赖Bean。Spring容器会自动检查XML配置文件的内容,为主调Bean注入依赖Bean。自动装配可以减少配置文件的工作量,但会降低依赖关系的透明性和清晰性。
  通过使用自动装配,可以让Spring插件自动将业务逻辑组件注入Struts2的Action实例中。通过设置struts.objectFactFactory.spring.autoWrite常量可以改变Spring插件的自动装配策略,该常量可以接受如下几个值:
  • name:使用byName自动装配(默认值)
  • type:使用byType自动装配
  • auto:Spring插件会自动检测需要时使用哪种自动装配方式
  • constructor:与type类似,区别是constructor使用构造器来构造注入所需的参数,而不是使用设值注入方式
代码示例详见:codes\08\8.7\autowire
  示例代码采用的是byName自动装配策略(默认值),而Struts2的配置文件与原来相同,Action的class属性指定实现类来创建Action实例,而使用Spring进行依赖注入,注入时采用的byName方式,因此只需要将Bean的ID与注入元素的名称一样,就可以进行自动注入了。
注意:整合Spring框架与不整合时当然存在区别,只是这个区别不在这个配置文件中体现,而是在创建该Action实例时体现出来的。如果不整合Spring框架,则Struts2框架负责创建Action实例,创建成功后就结束了;如果整合Spring框架,则当Action实例创建完成后,Spring插件还会负责将Action所需的业务逻辑组件注入给该Action实例。
这种方式的缺点:
  • Action与业务逻辑组件的耦合低到代码层次,必须在配置文件中配置与Action所需控制器同名的业务逻辑组件。这不利于高层次解耦。
  • Action接收Spring容器的自动装配,代码的可读性较差
参考资料:
《轻量级JavaEE企业应用实战 第四版》
JavaEE中web.xml中的load-on-startup属性
spring容器启动的三种方式
在Web应用中创建Spring容器的两种方式
最后修改时间:2017年4月5日18:23:32

************************************************************************结束语************************************************************************
  我在写这篇博客的时候也是一名初学者,有任何疑问或问题请留言,或发邮件也可以,邮箱为:fanxiaobin.fxb@qq.com,我会尽早的进行更正及更改。
在我写过的博客中有两篇博客是对资源的整理,可能对大家都有帮助,大家有兴趣的话可以看看!!
下载资料整理——目录:http://blog.csdn.net/fanxiaobin577328725/article/details/51894331
  这篇博客里面是我关于我见到的感觉不错的好资源的整理,里面包含了书籍及源代码以及个人搜索的一些资源,如果有兴趣的可以看看,我会一直对其进行更新和添加。
优秀的文章&优秀的学习网站之收集手册:http://blog.csdn.net/fanxiaobin577328725/article/details/52753638
  这篇博客里面是我对于我读过的,并且感觉有意义的文章的收集整理,纯粹的个人爱好,大家感觉有兴趣的可以阅读一下,我也会时常的对其进行更新。
************************************************************************感谢************************************************************************

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 监狱对死缓犯人延长转为无期怎么办 手机号码办理的宽带不想要了怎么办 朋友诈骗罪被关看守所了该怎么办 打架被拘留家里有孩子没人看怎么办 刑事拘留满37天给逮捕了怎么办 因打架被拘留十五天释放后会怎么办 犯罪人在拘留所生了小孩怎么办 我申请了进京证更换车辆怎么办 丈夫去世前想把财产留给妻子怎么办 假货中通代收货款发现是假货怎么办 注册志愿者时身份证被使用该怎么办 双眼皮贴贴的皮肤送了怎么办? 满60岁社保末满十五年怎么办 眼角膜少了一块怎么办应该吃什么 左右胸相差一个罩杯左右怎么办 穿一字肩的裙子没有无肩内衣怎么办 农业网柑橘被奄24小时怎么办 钱包被偷了小偷抓到了钱不认怎么办 快高考了很想学却没有动力怎么办? 孩子高三了学习状态不好怎么办 离婚时对方说把钱都花了怎么办 挂科太多学校不给毕业证怎么办 大专挂科太多学校让延期毕业怎么办 安卓手机老是收到垃圾短信怎么办 高铁站行李拉安检仪上应该怎么办 连壁金融立案了投资钱怎么办 联壁金融倒了投资人的钱怎么办 改签的高铁票错过了怎么办 高铁票错过了当天没别的车次怎么办 电脑文件剪切到u盘不见了怎么办 电脑剪切到u盘然后打不开了怎么办 淘宝未满十八岁限制购买物品怎么办 网上飞机订票手机号填写错了怎么办 室外回填土都是砂土压不实怎么办 王牌车新车储气筒漏气查不到怎么办 顺丰快递保价后商品出现问题怎么办 未保价快递丢失没有价值证明怎么办 安卓手机谷歌地图怎么用不了怎么办 ae模板版本太高打不开怎么办 苹果手机高德地图信号弱怎么办 网上订好火车票后没赶上火车怎么办