我们在平时的工作中,几乎不会看到下面的代码:
public static void main(String[] args) {
ApplicationContext apx = new ClassPathXmlApplicationContext("bean-factory.xml");
Car car = (Car) apx.getBean("car");
System.out.println(car);
}
上面的代码,其目的就是手动创建一个 Spring 容器,然后调用容器的 getBean() 方法从容器中获取对应的Bean。
但在现实的项目开发中,我们不会手动创建容器。比如,在Web工程中,我们根本不用管 Spring 容器的启动和创建,只需要在web.xml文件中配置一下,就可以使用 Spring 提供的能力。至于 Tomcat 是如何启动和创建 Spring 的,我们应该了解一下其大致的过程,这样在看源码的时候,不至于一头雾水。
在启动 Web 项目时,容器(比如 Tomcat )会读取 web.xml 配置文件中的两个节点
和
;那 Tomcat 为什么会读取呢?因为 ServletContextListener
接着 Tomcat 会创建一个 ServletContext
(上下文) 对象,该对象的应用范围,是整个 Web 项目都能使用这个上下文;
接着 Tomcat 会将读取到
转化为键值对,并交给 ServletContext
;
接着 Tomcat 会创建
中的类实例,即创建监听器。该监听器能够监听 ServletContext
对象的生命周期,实际上就是监听 Web 应用的生命周期。
当Tomcat启动或终止时,会触发ServletContextEvent
事件,该事件由ServletContextListener
来处理。
在ServletContextListener
接口中定义了处理ServletContextEvent
事件的两个方法。
注意:listener定义的类可以是自定义的类但必须需要继承 ServletContextListener
;
在监听的类中会有下面两个方法:
初始化方法:在这个方法中可以通过event.getServletContext().getInitParameter("XXXXX")
来得
到context-param
设定的值;
contextInitialized(ServletContextEvent event)
销毁方法: 在这个方法中,多用于关闭应用前释放资源,比如说数据库连接的关闭;
contextDestroyed(ServletContextEvent event)
得到这个 context-param 的值之后,你就可以做一些操作了。
注意,这个时候 Web 项目还没有完全启动完成,这个动作会比所有的Servlet都要早!
//配置文件的位置,存放在ServletContext中
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
//监听器类,用于监听ServletContext的生命周期
<listener>
<listener-class>com.scorpios.spring.listener.SpringServletContextListenerlistener-class>
listener>
<servlet>
<description>description>
<display-name>TestServletdisplay-name>
<servlet-name>TestServletservlet-name>
<servlet-class>com.scorpios.spring.servlet.TestServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>TestServletservlet-name>
<url-pattern>/TestServleturl-pattern>
servlet-mapping>
ServletContextListener
监听器,用于监听ServletContext
的创建和消亡(!!!很重要!!!)public class SpringServletContextListener implements ServletContextListener {
/*
* 当Servlet容器启动Web应用时调用该方法。在调用完该方法之后,容器再对Filter初始化,
* 并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
// 1. 获取 Spring 配置文件的名称.
ServletContext servletContext = sce.getServletContext();
String config = servletContext.getInitParameter("contextConfigLocation");
// 1. 创建 IOC 容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
// 2. 把 IOC 容器放在 ServletContext 的一个属性中.
servletContext.setAttribute("ApplicationContext", ctx);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
}
applicationContext.xml
<bean id="person" class="com.scorpios.spring.entity.Person">
<property name="username" value="scorpios">property>
bean>
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 从 application 域对象中得到 IOC 容器的引用
ServletContext servletContext = getServletContext();
ApplicationContext ctx = (ApplicationContext) servletContext.getAttribute("ApplicationContext");
// 2. 从 IOC 容器中得到需要的 bean
Person person = ctx.getBean(Person.class);
person.hello();
}
}
public class Person {
private String username;
public void setUsername(String username) {
this.username = username;
}
public void hello() {
System.out.println("My name is " + username);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body>
<a href="TestServlet">TestServleta>
body>
html>
(1)、ServletContext
即 Servlet
上下文对象,该对象表示当前的 Web 应用环境信息,一个Web 应用只会创建一个ServletContext
对象。Web 容器启动的时候,它会为每个Web应用程序都创建一个对应的ServletContext
对象,它代表当前的web应用。而ServletContextListener
就是监听该对象的状态。
(2)、由于一个 Web 应用中的所有Servlet共享一个ServletContext
对象,所以多个Servlet
通过ServletContext
对象实现数据共享,ServletContext
对象通常称为Context域对象。
(3)、我们在说到Servlet
的继承关系时,提到自定义的Servlet,实际上间接实现了Servlet
和ServletConfig
两个接口,其中==ServletConfig
接口中定义了一个方法叫getServletContext
(),用以获取
Servlet`运行的上下文环境对象。==
(4)、每个Web项目,运行时部署在Web应用服务器(如Tomcat、Jetty、WebLogic 等)下,我们称之为一个应用(Application)。我们知道一个Web应用里可以有多个Servlet,而这里的Servlet上下文就可以理解为这些Servlet的运行环境。
(1)、ServletContext
对象是在 Tomcat 服务器加载完当前Web应用后创建出来的(代表当前Web应用);
(2)、ServletContext
对象是作为ServletConfig
对象成员变量传入Servlet
中;
(3)、通过ServletConfig
的getServletContext()
方法就可以得到ServletContext
对象;
(4)、看下ServletConfig
中相关的ServletContext
代码:
//ServletConfig对象中维护了ServletContext对象的应用
class ServletConfig{
ServletContext context;
getInitParameter();
getInitParameterNames();
//返回一个ServletContext对象
public ServletContext getServletContext(){
return contex;
}
}
(5)、在Servet
中的init
的方法实例化一个ServletConfig
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
(6)、this.ServletConfig.getServletContext()
:通过ServletConfig
对象来获取ServletContext
对象。
ServletContext
对象:启动时创建
ServletConfig
对象:调用init
方法之前创建的,在ServletContext
对象之前。