使用gradle新建一个web工程,过程见:
http://blog.csdn.net/x_iya/article/details/68945373
build.gradle
group 'com.xiya'
version '1.0-SNAPSHOT'
apply plugin: 'idea'
apply plugin: 'war'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.akhikhl.gretty:gretty:+"
}
}
apply plugin: "org.akhikhl.gretty"
dependencies {
compile group: 'org.springframework', name: 'spring-webmvc', version: '4.3.7.RELEASE'
providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
建立一个测试类:
package com.xiya.beans;
/**
* Created by N3verL4nd on 2017/4/19.
*/
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.xiya.beans.Person">
<property name="name" value="lgh"/>
<property name="age" value="24"/>
</bean>
</beans>
在非web应用中,当我们使用IOC容器时可以直接
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
而在WEB应用中,IOC容器应该在被服务器加载的时候创建。对应于ServletContextListener的contextInitialized方法。
为了在其他组件中访问该IOC容器,可以把它放在ServletContext中。完整的代码:
package com.xiya.listeners;
/**
* Created by N3verL4nd on 2017/4/19.
*/
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class SpringServletContextListener implements ServletContextListener {
public SpringServletContextListener() {
}
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
//String configPath = servletContext.getInitParameter("contextConfigLocation");
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
servletContext.setAttribute("applicationContext", ctx);
}
public void contextDestroyed(ServletContextEvent sce) {
}
}
当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent 事件,该事件由 ServletContextListener 来处理。
在 ServletContextListener 接口中定义了处理ServletContextEvent 事件的两个方法。
contextInitialized(ServletContextEvent sce) :当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
contextDestroyed(ServletContextEvent sce) :当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。
我们编写个Servlet测试:
@WebListener
Servlet注解等价于在web.xml中的:
<listener> <listener-class>com.xiya.listeners.SpringServletContextListener</listener-class> </listener>
package com.xiya.servlets;
import com.xiya.beans.Person;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by N3verL4nd on 2017/4/19.
*/
@WebServlet("/hello.do")
public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
ApplicationContext ctx = (ApplicationContext) servletContext.getAttribute("applicationContext");
Person person = ctx.getBean(Person.class);
PrintWriter out = response.getWriter();
out.print(person);
out.close();
}
}
F:\>curl http://localhost:8080/SpringSpringMVC/hello.do
Person{name='lgh', age=24}
F:\>
实际上Spring对以上做了封装,我们可以直接使用,而不用自己额外编写listener:
ContextLoaderListener
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- <listener> <listener-class>com.xiya.listeners.SpringServletContextListener</listener-class> </listener>--> <!--配置Spring配置文件的名称和位置--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--启动IOC容器的ServletContextListener--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
如果我们不配置contextConfigLocation,则默认为WEB-INF目录下的applicationContext.xml
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]
ContextLoaderListener作用:在启动Web容器时,自动装配spring applicationContext.xml的配置信息。
因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。
@Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); }
核心方法:
this.context = createWebApplicationContext(servletContext);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
其中this.context为:
private WebApplicationContext context;
在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。
修改我们的servlet
package com.xiya.servlets;
import com.xiya.beans.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by N3verL4nd on 2017/4/19.
*/
@WebServlet("/hello.do")
public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//ServletContext servletContext = getServletContext();
//ApplicationContext ctx = (ApplicationContext) servletContext.getAttribute("applicationContext");
//Person person = ctx.getBean(Person.class);
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
Person person = context.getBean(Person.class);
PrintWriter out = response.getWriter();
out.print(person);
out.close();
}
}
如上,ApplicationContext的获取本质上还是执行如下方法:
ApplicationContext ctx = (ApplicationContext) getServletContext().
getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
在jsp中我们可以这样使用:
<%@ page import="org.springframework.web.context.support.WebApplicationContextUtils" %> <%@ page import="com.xiya.beans.Person" %><%-- Created by IntelliJ IDEA. User: N3verL4nd Date: 2017/4/20 Time: 8:32 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>测试</title> </head> <body> <% Person person = WebApplicationContextUtils.getWebApplicationContext(application).getBean(Person.class); %> <%=person%> </body> </html>
ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。
ServletContextListener的介绍:
http://www.cnblogs.com/homesea/p/4709403.html
http://pengranxiang.iteye.com/blog/1041265
所谓的 Spring 与 SpringMVC 整合,就是让 SpringMVC 如何使用 Spring 的 IOC 容器。