`
winworm
  • 浏览: 4218 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Spring bean上下文环境在web环境的初始化概述

阅读更多
 
 
spring web服务在tomcat容器中启动的流程
 
 
在介绍spring启动流程之前,先介绍2个概念 servlet ServletContext
servlet java web服务的核心组件,可以简单理解为servlet是能接收并处理web请求的服务(典型的就是http请求)
ServletContext 是生成并维护servlet的上下文,存在于特定容器之中,如tomcatjettyresin等等
 
容器启动过程中解析web.xml 文件,它描述了一个web服务的关键信息,一般情况下包括servlet filterlistener
 
容器启动时将通知相关的listener,一般情况下spring环境就是这个时候引入的。
执行相关Servlet(如果设置为容器启动时执行)
filter初始化并执行init方法
filterservlet接收请求过程中之前都会执行
 
 
下面介绍spring 是如何在web环境中被初始化的
 
StandardContext.listenerStart() 启动web.xml 中配置的监听器(这个监听器在容器初始化时执行)
这里的StandardContext就是tomcat容器中的servlet环境
 
 
 
 
 
 
 
 
 
 
 
从上面可以看出,启动过程为,tomcat容器读取web.xml 初始化servlet容器StandardContext,配置listenerfilterservlet,初始化成功后触发相应的监听器,servlet(如果设置为load-on-startup
 
 
 
现在看集成springweb项目一般的web.xml示例:
 
<?xmlversion="1.0"encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>zhixiao.root</param-value>
</context-param>
<!-- session timeout, minutes unit -->
<session-config>
<session-timeout>10</session-timeout>
</session-config>
<!-- default home page -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<display-name>parking Created Web Application</display-name>
<!-- sprint/* -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener> <!-- 可以去掉,因为spring mvc DispatchServlet 支持request session 作用范围的bean -->
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<!-- Spring 刷新Introspector防止内存泄露 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<!-- encoding -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- redis session接管 -->
<filter>
<display-name>RedisSessionFilter</display-name>
<filter-name>RedisSessionFilter</filter-name>
<filter-class>com.qhyu.zhixiao.session.RedisSessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RedisSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<!-- ip checking -->
<filter>
<filter-name>ipFilter</filter-name>
<filter-class>com.qhyu.zhixiao.filter.IpFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ipFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
 
<!-- springmvc -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
</web-app>
 
 
 
下面重点看 ContextLoaderListener
 
这个listenertomcat容器启动时执行
 
publicclass ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
/**
* Initialize the root web application context.
*/
@Override
publicvoid contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
@Override
publicvoid contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
 
initWebApplicationContext 方法就是初始化spring的入口,参数就是tomcat容器初始化的servlet
 
 
进入
initWebApplicationContext方法主要干了两件事
1.初始化WebApplicationContext
WebApplicationContext context = null;
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
通过java反射机制生成ConfigurableWebApplicationContext类对象,它就是springbean生成运行环境(BeanFactory容器
 
2. 刷新初始化webApplication
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
configureAndRefreshWebApplicationContext(cwac,servletContext);
 
 
 
 
生成好spring上下文对象后,进入configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc)方法,主要执行代码如下:
 
wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);//spring 上下文设置spring bean配置文件路径
}
 
ConfigurableEnvironment env = wac.getEnvironment();
if (envinstanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);
wac.refresh();
 
 
这里有一个注意的地方,ConfigurableEnvironment生成的地方,
wac.setConfigLocation(configLocationParam); 时根据 configLocationParam设置配置参数路径时就会初始化StandardServletEnvironmentConfigurableEnvironment的子类)
 
 
进入AbstractApplicationContext.refresh()方法
 
publicvoid refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
 
// Propagate exception to caller.
throwex;
}finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
 
 
 
(1)prepareRefresh()
// Initialize any placeholder property sources in the context environment
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
 
(2) obtainFreshBeanFactory();此方法负责创建beanFactory并根据spring xml配置文件初始化得到BeanDefintions
 
 
 
 
这里主要看XmlWebApplicationContext类的loadBeanDefinitions方法
从上图看一看出,是如何一步一步的解析xml文件的
主要代码在NamespaceHandler,根据命名空间得到相应的处理器来解析相关配置文件中的标签tag
得到的handler为:org.springframework.context.config.ContextNamespaceHandler
其实就是从springjar包配置文件中获取的
publicclass ContextNamespaceHandler extends NamespaceHandlerSupport {
 
@Override
publicvoid init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
 
}
 
应该可以明显看出,xml中的标签就是通过这些handler来处理的
通过handler中注册的parser来解析tag
 
下面再来看下是如何解析的
通过tag名称,得到相应的解析器并做相应的处理
 
 
 
上面实例就是解析property-placeholder标签的parser
 
 
 
 
回到refresh()方法,可以看到obtainFreshBeanFactory();其实已经干了大部分工作了,创建spring bean上下文beanFactory 并解析xml得到beanDefintion初始化上下文。
 
下一步执行prepareBeanFactory(beanFactory);方法
 
这个方法主要是对beanFactory做一些初始化工作
1)设置classLoader
2)设置SpEL表达式解析
3)设置ResourceEditorRegistrar(在获取bean中设置value
4)设置前置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
5)设置一些不需要autowiredbean
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
ApplicationContextAware子类不通过autowired方式注入
6)设置和环境相关的beans
 
 
prepareBeanFactory之后执行postProcessBeanFactory
主要设置了一些前置处理器。
 
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
 
后续就是注册资源文件,监听器,实例化一些非延迟加载的bean,最后广播相关事件 over
 
 
 
总结:
spring家族中所有的部件都是基于spring bean容器的,了解beanFactory上下文的结构和原理对理解spring十分重要,本文主要从整体上描述了spring 如何在web环境中初始化启动,从源码上给出了一个简要的流程描述,希望读者仔细阅读后能对spring bean容器有一个系统的了解。
 
 
 
 
参考:
2.http://www.cnblogs.com/RunForLove/p/5688731.html
分享到:
评论

相关推荐

    让spring解决控制springboot中bean的加载顺序的问题.docx

    只需要把需要注册进容器的bean声明为@Component即可,spring会自动扫描到这个Bean完成初始化并加载到spring上下文容器。 而当你在项目启动时需要提前做一个业务的初始化工作时,或者你正在开发某个中间件需要完成...

    Spring在web下启动流程学习笔记

    Spring学习笔记,主要是在tomcat环境下spring上下文的启动,初始化,bean配置的载入等

    spring源代码解析

    从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然后可以读到配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根上下文。当这个根上...

    Spring in Action(第二版 中文高清版).part2

    2.5.3 初始化和销毁Bean 2.6 小结 第3章 高级Bean装配 3.1 声明父Bean和子Bean 3.1.1 抽象基Bean类型 3.1.2 抽象共同属性 3.2 方法注入 3.2.1 基本的方法替换 3.2.2 获取器注入 3.3 注入非Spring Bean ...

    Spring in Action(第二版 中文高清版).part1

    2.5.3 初始化和销毁Bean 2.6 小结 第3章 高级Bean装配 3.1 声明父Bean和子Bean 3.1.1 抽象基Bean类型 3.1.2 抽象共同属性 3.2 方法注入 3.2.1 基本的方法替换 3.2.2 获取器注入 3.3 注入非Spring Bean ...

    Spring in Action(第2版)中文版

    2.5.3初始化和销毁bean 2.6小结 第3章高级bean装配 3.1声明父bean和子bean 3.1.1抽象基bean类型 3.1.2抽象共同属性 3.2方法注入 3.2.1基本的方法替换 3.2.2获取器注入 3.3注入非springbean 3.4注册自定义...

    spring boot源码

    spring boot源代码,通过源代码可以了解spring boot底层运行机制。 1. 初始化各种属性,加载成...4. 在上下文刷新之后且所有的应用和命令行运行器被调用之前发送 ApplicationStartedEvent。 5. 在应用程序和命令行运行

    Spring中文帮助文档

    2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到Spring 2.5 2.7.1. 改变 2.8. 更新的样例应用 2.9. 改进的文档 I. 核心技术 3. IoC(控制反转)...

    Spring API

    2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到Spring 2.5 2.7.1. 改变 2.8. 更新的样例应用 2.9. 改进的文档 I. 核心技术 3. IoC(控制反转)...

    Spring启动流程.java

    //在上下文环境中初始化任何占位符属性源 getEnvironment().validateRequiredProperties();//验证所有标记为必需的属性都是可解析的 this.earlyApplicationEvents = new LinkedHashSet();//保存容器中的一些早期的...

    Spring攻略(第二版 中文高清版).part1

    2.7 自定义Bean初始化和析构 72 2.7.1 问题 72 2.7.2 解决方案 72 2.7.3 工作原理 72 2.8 用Java Config简化XML配置 77 2.8.1 问题 77 2.8.2 解决方案 77 2.8.3 工作原理 77 2.9 使Bean感知容器 ...

    spring-framework-3.1.0.RELEASE.zip

    Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。... 1、核心容器 2、Spring 上下文 3、Spring AOP 4、Spring DAO 5、Spring ORM 6、Spring Web 模块 7、Spring MVC 框架

    Spring攻略(第二版 中文高清版).part2

    2.7 自定义Bean初始化和析构 72 2.7.1 问题 72 2.7.2 解决方案 72 2.7.3 工作原理 72 2.8 用Java Config简化XML配置 77 2.8.1 问题 77 2.8.2 解决方案 77 2.8.3 工作原理 77 2.9 使Bean感知容器 ...

    Spring面试题

    ☆ Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域...

    SpringBoot启动过程-mind版.md

    2. **初始化应用上下文:** Spring Boot会创建一个应用上下文(ApplicationContext),该上下文包含了应用中所有的Bean定义、配置信息等。它是整个应用的核心,用于管理Bean的生命周期和依赖关系。 3. **执行自动...

    spring-example-conditional:带有 Spring Boot 的自定义 Spring 4 @Conditional 注释示例

    为什么重要Spring Boot 项目自动配置支持依赖于 @Conditional - 它有自己的构造型注释,如或来初始化 Spring 上下文,以便依赖于类路径(或适用于任何其他条件的其他自定义条件注释)。这个例子此示例展示了如何将...

    【预习资料】Spring Boot 运行机制源码剖析1

    //初始化主要加载资源类集合并去重配置Spring Boot Bean源Java 配置 Class 或 XML 上下文配置文件集合,用于 Spring Boot

    spring-training:Spring Framework简介和示例

    Spring培训 1. Hello World(helloworld) 基本的hello world应用程序,具有... 仅在可感知网络的Spring ApplicationContext上下文中有效。 会议 这将bean定义的作用域限定为HTTP会话。 仅在可感知网络的Spring Ap

    spring-experiement

    假设bean是单例的,并且没有配置为延迟初始化的,那么它将在上下文启动时创建。 getBean()只是把它捞出来。 延迟初始化Bean仅在首次引用时进行初始化,但这不是默认设置。 范围限定的bean(例如,原型作用域)也仅...

    test-conditonal-error:条件中已识别上下文访问错误的样本

    由于条件在Spring-boot上下文生命周期中很早就已处理,因此在处理bean初始化时可能尚未加载自动接线处理器:然后初始化初始化的bean(通过实例搜索访问)而不进行自动装配处理,并且由于它们是单例的,因此它们永远...

Global site tag (gtag.js) - Google Analytics