spring容器启动原理分析1
在项目的web.xml中配置
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
此配置为spring容器加载入口,因为其javax.servlet.ServletContextListener接口。
下面代码为ServletContextListener的源码:
- public interface ServletContextListener extends EventListener {
- /**
- ** Notification that the web application initialization
- ** process is starting.
- ** All ServletContextListeners are notified of context
- ** initialization before any filter or servlet in the web
- ** application is initialized.
- */
- public void contextInitialized ( ServletContextEvent sce );
- /**
- ** Notification that the servlet context is about to be shut down.
- ** All servlets and filters have been destroy()ed before any
- ** ServletContextListeners are notified of context
- ** destruction.
- */
- public void contextDestroyed ( ServletContextEvent sce );
- }
其中contextInitialized方法为web应用加载入口,实现此方法即可在其中加载自定义初始化web应用。
回过头看ContextLoaderListener中的初始化工作:
- /**
- * Initialize the root web application context.
- */
- public void contextInitialized(ServletContextEvent event) {
- this.contextLoader = createContextLoader();
- if (this.contextLoader == null) {
- this.contextLoader = this;
- }
- this.contextLoader.initWebApplicationContext(event.getServletContext());
- }
其具体初始化工作在其父类org.springframework.web.context.ContextLoader中的initWebApplicationContext方法中进行:
- /**
- * Initialize Spring's web application context for the given servlet context,
- * using the application context provided at construction time, or creating a new one
- * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
- * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
- * @param servletContext current servlet context
- * @return the new WebApplicationContext
- * @see #ContextLoader(WebApplicationContext)
- * @see #CONTEXT_CLASS_PARAM
- * @see #CONFIG_LOCATION_PARAM
- */
- public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
- if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
- throw new IllegalStateException(
- "Cannot initialize context because there is already a root application context present - " +
- "check whether you have multiple ContextLoader* definitions in your web.xml!");
- }
- Log logger = LogFactory.getLog(ContextLoader.class);
- servletContext.log("Initializing Spring root WebApplicationContext");
- if (logger.isInfoEnabled()) {
- logger.info("Root WebApplicationContext: initialization started");
- }
- long startTime = System.currentTimeMillis();
- try {
- // Store context in local instance variable, to guarantee that
- // it is available on ServletContext shutdown.
- if (this.context == null) {
- this.context = createWebApplicationContext(servletContext);
- }
- if (this.context instanceof ConfigurableWebApplicationContext) {
- ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
- if (!cwac.isActive()) {
- // The context has not yet been refreshed -> provide services such as
- // setting the parent context, setting the application context id, etc
- if (cwac.getParent() == null) {
- // The context instance was injected without an explicit parent ->
- // determine parent for root web application context, if any.
- ApplicationContext parent = loadParentContext(servletContext);
- cwac.setParent(parent);
- }
- configureAndRefreshWebApplicationContext(cwac, servletContext);
- }
- }
- servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
- ClassLoader ccl = Thread.currentThread().getContextClassLoader();
- if (ccl == ContextLoader.class.getClassLoader()) {
- currentContext = this.context;
- }
- else if (ccl != null) {
- currentContextPerThread.put(ccl, this.context);
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
- WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
- }
- if (logger.isInfoEnabled()) {
- long elapsedTime = System.currentTimeMillis() - startTime;
- logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
- }
- return this.context;
- }
- catch (RuntimeException ex) {
- logger.error("Context initialization failed", ex);
- servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
- throw ex;
- }
- catch (Error err) {
- logger.error("Context initialization failed", err);
- servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
- throw err;
- }
- }
下面我们来分析一下上面的方法中的具体工作:
1)方法determineContextClass其返回一个WebApplicationContext的实现类,要么是默认的XmlWebApplicationContext,要么是一个指定的自定义的类。
先看方法源码:
- /**
- * Return the WebApplicationContext implementation class to use, either the
- * default XmlWebApplicationContext or a custom context class if specified.
- * @param servletContext current servlet context
- * @return the WebApplicationContext implementation class to use
- * @see #CONTEXT_CLASS_PARAM
- * @see org.springframework.web.context.support.XmlWebApplicationContext
- */
- protected Class<?> determineContextClass(ServletContext servletContext) {
- String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
- if (contextClassName != null) {
- try {
- return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
- }
- catch (ClassNotFoundException ex) {
- throw new ApplicationContextException(
- "Failed to load custom context class [" + contextClassName + "]", ex);
- }
- }
- else {
- contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
- try {
- return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
- }
- catch (ClassNotFoundException ex) {
- throw new ApplicationContextException(
- "Failed to load default context class [" + contextClassName + "]", ex);
- }
- }
- }
先查看是否有用户自定义的context类,其配置方式是在web.xml中配置初始化属性其name为contextClass,原因是:
- /**
- * Config param for the root WebApplicationContext implementation class to use: {@value}
- * @see #determineContextClass(ServletContext)
- * @see #createWebApplicationContext(ServletContext, ApplicationContext)
- */
- public static final String CONTEXT_CLASS_PARAM = "contextClass";
在web.xml中的配置例如:
- <context-param>
- <param-name>contextClass</param-name>
- <param-value>xxxxxxxxxx</param-value>
- </context-param>
如果没有自定义配置的话,实现加载其默认WebApplicationContext实现类org.springframework.web.context.support.XmlWebApplicationContext。
2)方法createWebApplicationContext将determineContextClass方法返回的Class类实例化。并将其实例类向上转型为ConfigurableWebApplicationContext类型。
默认的返回应该是ConfigurableWebApplicationContext的子类org.springframework.web.context.support.XmlWebApplicationContext实例。
下面是方法的源码:
- /**
- * Instantiate the root WebApplicationContext for this loader, either the
- * default context class or a custom context class if specified.
- * <p>This implementation expects custom contexts to implement the
- * {@link ConfigurableWebApplicationContext} interface.
- * Can be overridden in subclasses.
- * <p>In addition, {@link #customizeContext} gets called prior to refreshing the
- * context, allowing subclasses to perform custom modifications to the context.
- * @param sc current servlet context
- * @return the root WebApplicationContext
- * @see ConfigurableWebApplicationContext
- */
- protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
- Class<?> contextClass = determineContextClass(sc);
- if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
- throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
- "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
- }
- return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
- }
3)方法configureAndRefreshWebApplicationContext配置web应用
源码为:
- protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
- if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
- // The application context id is still set to its original default value
- // -> assign a more useful id based on available information
- String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
- if (idParam != null) {
- wac.setId(idParam);
- }
- else {
- // Generate default id...
- if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
- // Servlet <= 2.4: resort to name specified in web.xml, if any.
- wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
- ObjectUtils.getDisplayString(sc.getServletContextName()));
- }
- else {
- wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
- ObjectUtils.getDisplayString(sc.getContextPath()));
- }
- }
- }
- wac.setServletContext(sc);
- String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);
- if (initParameter != null) {
- wac.setConfigLocation(initParameter);
- }
- customizeContext(sc, wac);
- wac.refresh();
- }
其中String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);获取在web.xml中配置的contextConfigLocation参数来确定spring配置文件的位置。
其中的ConfigurableWebApplicationContext类型参数实际上是其子类org.springframework.web.context.support.XmlWebApplicationContext的类型参数,
其中方法customizeContext是定制化conext的方法,如果没有在web.xml中配置contextInitializerClasses初始化参数则此方法不做任何工作。
其中wac.refresh();方法其是在org.springframework.web.context.support.XmlWebApplicationContext的父类org.springframework.context.support.AbstractApplicationContext中实现。它才开始真正的spring配置工作。
spring容器启动原理分析1的更多相关文章
- Spring Boot 启动原理分析
https://yq.aliyun.com/articles/6056 转 在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启 ...
- spring boot启动原理步骤分析
spring boot最重要的三个文件:1.启动类 2.pom.xml 3.application.yml配置文件 一.启动类->main方法 spring boot启动原理步骤分析 1.spr ...
- 从头看看Tomcat启动Spring容器的原理
通过带注解Spring Boot可以启动一个web容器,并初始化bean容器.那么Tomcat启动并初始化spring容器的原理是怎样的? Tomcat启动web程序时会创建一对父子容器(图1): 有 ...
- Spring5深度源码分析(三)之AnnotationConfigApplicationContext启动原理分析
代码地址:https://github.com/showkawa/spring-annotation/tree/master/src/main/java/com/brian AnnotationCon ...
- Spring Boot -- 启动流程分析之ApplicationContext 中
上一节我们已经分析到AbsractApplicationContext类refresh方法中的postProcessBeanFactory方法,在分析registerBeanPostProcessor ...
- SpringBoot启动原理分析
用了差不多两年的SpringBoot了,可以说对SpringBoot已经很熟了,但是仔细一想SpringBoot的启动流程,还是让自己有点懵逼,不得不说是自己工作和学习的失误,所以以此文对Spring ...
- Spring依赖注入原理分析
在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ...
- Spring Boot启动原理解析
Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置 ...
- spring容器IOC原理解析
原理简单介绍: Spring容器的原理,其实就是通过解析xml文件,或取到用户配置的bean,然后通过反射将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这些bean ...
随机推荐
- Beta阶段项目复审
复审人:王李焕 六指神功:http://www.cnblogs.com/teamworkers/ wt.dll:http://www.cnblogs.com/TeamOf/ 六个核桃:http://w ...
- 201521123107 《Java程序设计》第4周学习总结
第4周作业-面向对象设计与继承 1.本周学习总结 2.书面作业 1.注释的应用 使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图) 对类的注释: 所得到的效果: ...
- 201521123105 第四周Java学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 继承与多态的概念与实现父类与之类的关系解决代码复用的办法 2. 书面作业 2.1 将在网上商 ...
- 201521123007《Java程序设计》第11周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1. 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) ...
- 201521123103 《java学习笔记》 第十四周学习总结
一.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 二.书面作业 1. MySQL数据库基本操作 1.1建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现 ...
- 201521123106 《Java程序设计》第14周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...
- 杭电acm-2007平方和立方和
#include<stdio.h>int main(){ int t,m,n,x,y,i; while(scanf("%d%d",&n, ...
- 深入理解计算机系统(2.5)------C语言中的有符号数和无符号数以及扩展和截断数字
上一篇博客我们讲解了计算机中整数的表示,包括无符号编码和补码编码,以及它们之间的互相转换,个人觉得那是非常重要的知识要点.这篇博客我们将介绍C语言中的有符号数和无符号数以及扩展和截断数字. 1.C语言 ...
- 框架应用:Mybatis (一) - 入门案例
ORM框架 在实际开发中,工程中本质的任务是从数据库中获取数据,然后对数据进行操作,又或者写入数据.开发时语言是大多是面向对象的工程语言,这个时候就必须进行工程语言和数据库连接语言的转换,也就是所谓的 ...
- Eclipse dynamic web project 插件
下载了Eclipse Oxygen 发现没有Dynamic web Project 首先我们先了解下Dynamic Web Project If you want to create a c ...