您的位置:首页 > 编程语言 > Java开发

【spring】IOC容器在WEB容器中的启动

2017-06-16 19:14 555 查看
在非web项目中,我们可以通过在main方法中直接创建IOC容器。而在web项目中,IOC容器是如何创建的?IOC

容器是如何在web容器中启动的?这就是本篇博客要阐述的问题,下面我们先从一个实例出发。

【简单实例】

1. 新建一个java web项目,创建web.xml和applicationContext.xml两个配置文件,前者是对web容器的管理

,后者是对spring ioc容器的管理。

2. 新建一个简单的bean,其中包含username属性,hello方法可输出配置的属性名称。


package com.hzt.spring.struts2.beans;

public class Person {

private String username;

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

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

}


3. 新建一个监听器SpringServletContextListener,并且实现ServletContextListener接口,实现


contextInitialized()方法,将IOC容器至于ServletContext中。


package com.hzt.spring.struts2.listeners;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* Application Lifecycle Listener implementation class SpringServletContextListener
*
*/
public class SpringServletContextListener implements ServletContextListener {

/**
* Default constructor.
*/
public SpringServletContextListener() {
// TODO Auto-generated constructor stub
}

/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent arg0) {
//1. 获取spring配置文件的名称
ServletContext servletContext = arg0.getServletContext();
String config = servletContext.getInitParameter("configLocation");

//1. 创建IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

//2. 把IOC容器放在servletContext的一个属性中
servletContext.setAttribute("ApplicationContext", ctx);
}

/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}

}


4. 新建一个TestServlet,继承HttpServlet,重写其中的doGet()方法,测试是否能从web容器中获取到IOC


容器,并且获取到对应的bean。

package com.hzt.spring.struts2.servlets;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationContext;

import com.hzt.spring.struts2.beans.Person;

public class TestServlet extends HttpServlet{

/**
*
*/
private static final long serialVersionUID = 1L;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
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. 在web.xml中配置spring的配置文件,并添加上面写好的监听器。


<?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_2_5.xsd" id="WebApp_ID" version="2.5">
<!-- 配置spring配置文件的名称和位置 -->
<context-param>
<param-name>configLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>com.hzt.spring.struts2.listeners.SpringServletContextListener</listener-class>
</listener>
</web-app>


6. 在applicationContext.xml中配置bean


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> 
<bean id="person" class="com.hzt.spring.struts2.beans.Person">
<property name="username" value="hzt"></property>
</bean>
</beans>


此实例结果可以在控制台看到输出了hello方法中的信息结果,也就是我们通过一个小例子实现了在Web容器


中去管理IOC容器的。

【过程一览】


上图是:在web容器中启动spring应用程序的过程。

【过程分析】

有了上面的实例基础以及一张过程图,下面我们进一步结合着spring的源码来分析一下整个过程。

1. 对于web应用程序,我们都会在web.xml中配置一个spring监听器,即ContextLoaderListener,如下:


 <!-- 配置IOC容器的 SpringServletContextListener -->
<listener>
 	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

此监听器继承ContextLoader,并且实现了ServletContextListener,其中包含四个方法,分别是两个构造函

数(无参和WebApplicationContext参数)、初始化Context和销毁Context.


2. 在初始化方法contextInitialized()中,实际上是通过ContextLoader类中的initWebApplicationContext()去初始

化的。

其中,初始化逻辑大致可归纳为以下几个步骤:

1) 判断是否存在根上下文,若存在,则直接抛异常,已存在根上下文,不可实现初始化。

2) 输出servletContext.log("Initializing Spring root WebApplicationContext");日志信息,则说明当

前不存在根下上文。

3) 如果当前不存在context,则会创建上下文createWebApplicationContext(Servlet Context)

4) 如果当前存在ConfigurableWebApplicationContext的实例,则会去判断其父容器,若存在父容器,则会

直接启动IOC容器configureAndRefreshWebApplicationContext(cwac,servletContext);若父容器为null,则

loadParentContext(ServletContext),并将结果set到子容器中。

5) 最后会给全局的上下文环境设置属性,根上下文和上下文,即

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,

this.context);

总结来说,其上述整个过程主要是ContextLoader做的两件事:一是在Web容器中建立双亲IOC容器;

二是生成对应的webApplicationContext并将其初始化。

【上下文相关】

1. 对于一个Web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,也就是

ServletContext,其为spring IOC容器提供宿主环境。

2. contextInitialized()方法被调用时,spring会启动一个上下文,这个上下文被称为根上下文,即

WebApplicationContext.

3. 在web.xml中,我们通常会配置多个Servlet,每个Servlet都会有自己的一个上下文,称为子上下文,它

也保存在Servlet Context中。

4.  父上下文(父容器)和子上下文(子容器)的访问权限:子上下文可以访问父上下文中的bean,但是父

上下文不可以访问子上下文中的bean。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: