1. 概述
表现层和业务层整合:
1. Jsp/Servlet整合Spring;
2. Spring MVC整合SPring;
3. Struts2整合Spring;
本文主要介绍Jsp/Servlet整合Spring原理及源码分析。
2. 整合过程
Spring&WEB整合,主要介绍的是Jsp/Servlet容器和Spring整合的过程,当然,这个过程是Spring MVC或Strugs2整合Spring的基础。
Spring和Jsp/Servlet整合操作很简单,使用也很简单,按部就班花不到2分钟就搞定了,本节只讲操作不讲原理,更多细节、原理及源码分析后续过程陆续涉及。
(1)导入必须的jar包,本例spring-web-x.x.x.RELEASE.jar;
(2)配置web.xml,本例示例如下;
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>spring</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
只需要配置context-param和listener就够了。配置项的内容含义:ServletContext.setAttribute(“contextConfigLocation”, “applicationCOntext.xml”),而中配置的侦听器则来自于第一步中导入的spring-web-x.x.x.RELEASE.jar包。
就这么两步,Spring和Jsp/Servlet就已经整合好了,验证一下,启动tomcat不报错就可以了。
3. 整合原理
原理:让Spring容器随着tomcat容器ServletContext的启动而启动,并且在初始化完成后放到整个应用都可以访问的范围。
回想一下,在非web环境下,使用Spring是需要我们手动把ApplicationContext对象创建出来使用。在web环境下,使用Spring也是需要把ApplicationContext对象创建出来,不过这个步骤大可交给服务器来做,你不必自己再去写个单例类,web环境中单例对象多了去了,servlet是单例的,filter是单例的,listener也是单例,这三个,随便找一个在初始化的时候把ApplicationContext对象创建出来,然后放到整个应用都可以访问的ServletContext容器中就可以了。
总结一下:
(1)让ApplicationContext随着服务器的启动而启动,可以借助与Servlet/Filter/Listener任何一个;
(2)把创建好的ApplicationContext放到ServletContext中,整个应用范围,想怎访问就怎么访问;
整合原理就这么多,你自己分分钟都可以整一个出来,至于代码健不健壮再说,先用再调嘛。但是大可不必这么麻烦,Spring已经把这一切做好了,你只要拿过来用就可以了。
回顾一下第一节的内容,导入一个jar包spring-web-x.x.x.RELEASE.jar,配置了一个侦听器listener,没错,上面的原理都被这个jar包中的这个侦听器给实现了。早期的Spring整合web,支持servlet和listener,不过在Spring 3.x的时候,Spring官方访问已经明确不支持Servlet方式并且已经将相关源码移出web的jar包,所以现在Spring整合WEB,就一条路,listener。
有了ApplicationContext对象,IOC/DI、AOP、Spring JDBC以及事务、国际化ResourceMessage、Spring事件机制、FactoryBean、Spring JNDI等等,想怎么用怎么用。
再分析源码之前,介绍一个工具,org.springframework.web.context.support.WebApplicationContextUtils,这是Spring官方提供的一个web环境下便捷从ServletContext中获取ApplicationContext的工具类,使用示例如下所示。
WebApplicationContext applicationContext = WebApplicationContextUtils.
getWebApplicationContext(this.getServletContext());
你不用再去记忆ApplicationContext放入ServletContext中冗长的key,这个方法的源码也很简单,不过Spring写的又臭又长,原理如下所示。
/**
* String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE =
* WebApplicationContext.class.getName() + ".ROOT";
*/
WebApplicationContext context = (WebApplicationContext) this.getServletContext()
.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
好了,有了以上的铺垫,并且你对Spring熟悉,那么在web环境下使用Spring对你来说已经毫无压力。
4. 源码分析
4.1 contextInitialized
ServletContextListener侦听器是Jsp/Servlet规范中八大侦听器之一,用来监听ServletContext的创建和销毁。第一节中配置的侦听器ContextLoaderListener就实现了该接口。
package org.springframework.web.context;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
/**
* 该方法实现与ServletContextListener接口
* 当ServletContext被创建之后,服务器会自动调用该方法
* 而该方法就是Spring整合WEB的入口
*/
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* 该方法实现与ServletContextListener接口
* 当ServletContext销毁的时候,服务器会自动调用该方法
* 最后一节详解该方法
*/