Web工程是如何启动和创建Spring IOC容器的?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxd1435513775/article/details/83064573

一、引言

我们在平时的工作中,可能很少会看到下面的代码:

	public static void main(String[] args) {
	
		ApplicationContext apx = new ClassPathXmlApplicationContext("bean-factory.xml");
		Car car = (Car) apx.getBean("car");
		System.out.println(car);

	}

上面代码会在测试Spring容器的时,在测试类中遇见,其目的就是手动创建一个Spring IOC容器,然后用getBean()方法从容器中对于的类。但在真正的项目中,我们几乎不会手动创建容器,比如,在Web工程中,我们根本不用管Spring IOC容器的启动和创建,只需要在web.xml文件中配置一下,就可以使用Spring的能力了。至于Tomcat是如何启动和创建Spring的,我们应该了解一下其大致的过程,这样在看源码的时候,不至于一头雾水,下面来学习一下。

二、Tomcat项目是如何启动的?

第一步:
在启动Web项目时,容器(比如Tomcat)会读取web.xml配置文件中的两个节点<contex-param>和<listener>;
第二步:
接着Tomcat会创建一个ServletContext(上下文)对象,该对象的应用范围,是整个Web项目都能使用这个上下文;
第三步:
接着Tomcat会将读取到<context-param>转化为键值对,并交给ServletContext;
第四步:
接着Tomcat会创建<listener></listener>中的类实例,即创建监听器。
该监听器能够监听 ServletContext对象的生命周期,实际上就是监听 Web 应用的生命周期。
当Tomcat启动或终止时,会触发ServletContextEvent事件,该事件由ServletContextListener来处理。
在ServletContextListener接口中定义了处理ServletContextEvent事件的两个方法。

注意:listener定义的类可以是自定义的类但必须需要继承ServletContextListener;

第五步:
在监听的类中会有下面两个方法:
初始化方法:
	contextInitialized(ServletContextEvent event)
	//在这个方法中可以通过event.getServletContext().getInitParameter("XXXXX") 来得
	到context-param设定的值;
销毁方法:	
	contextDestroyed(ServletContextEvent event) 
	//在这个方法中,多用于关闭应用前释放资源,比如说数据库连接的关闭;
第六步:
得到这个context-param的值之后,你就可以做一些操作了

注意,这个时候你的Web项目还没有完全启动完成,这个动作会比所有的Servlet都要早;

三、Tomcat启动时如何集成Spring?

1、web.xml配置文件
//配置文件的位置,存放在ServletContext中
<context-param>
   	<param-name>contextConfigLocation</param-name>
   	<param-value>classpath:applicationContext.xml</param-value>
</context-param>
  
 //监听器类,用于监听ServletContext的生命周期
<listener>
  	<listener-class>com.scorpios.spring.listener.SpringServletContextListener</listener-class>
</listener>
 
<servlet>
    <description></description>
    <display-name>TestServlet</display-name>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>com.scorpios.spring.servlet.TestServlet</servlet-class>
</servlet>

<servlet-mapping>
  	<servlet-name>TestServlet</servlet-name>
    <url-pattern>/TestServlet</url-pattern>
</servlet-mapping>
2、自定义的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

	}

}
3、Spring的配置文件applicationContext.xml
	<bean id="person"  class="com.scorpios.spring.entity.Person">
		<property name="username" value="scorpios"></property>	
	</bean>
4、用于测试的TestServlet
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();
	}
}
5、实体类
public class Person {

	private String username;

	public void setUsername(String username) {
		this.username = username;
	}

	public void hello() {
		System.out.println("My name is " + username);
	}

}
6、测试的jsp页面
	<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
	<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
	<html>
	<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Insert title here</title>
	</head>
	<body>

		<a href="TestServlet">TestServlet</a>
		
	</body>
	</html>

四、测试结果

在这里插入图片描述

在这里插入图片描述


补充介绍:

1、ServletContext对象

(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 etc.)下,我们称之为一个应用(Application)。我们知道一个Web应用里可以有多个Servlet,而这里的Servlet上下文就可以理解为这些Servlet的运行环境。

2、ServletContext创建时机

(1)、ServletContext对象是在TomCat服务器加载完当前Web应用后创建出来的(代表当前Web应用);
(2)、ServletContext对象是作为ServletConfig对象成员变量传入Servlet中;
(3)、通过ServletConfig的getServletContext()方法就可以得到ServletContext对象;
(4)、看下ServletConfig中相关的ServletContext代码:

class ServletConfig{      //ServletConfig对象中维护了ServletContext对象的应用
    ServletContext context;
    getInitParameter();
    getInitParameterNames();
    public ServletContext getServletContext(){     //返回一个ServletContext对象
      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对象之前。

猜你喜欢

转载自blog.csdn.net/zxd1435513775/article/details/83064573