由源码理解spring初始化过程
来源:互联网 发布:淘宝回收充值卡 编辑:程序博客网 时间:2024/06/13 20:20
0.WebApplicationContext必须有web容器才能启动,常见的web容器是ServletContext实例,我们可以在web.xml配置自启动的Servlet或者定义ServletContextListener(web容器的监听器),只需要定义其中一个即可完成启动Spring的WebApplicationContext的相应工作。
1. org.springframework.web.context.ContextLoaderListener类进行容器的初始化时,该类会被Web容器(如Tomcat)自动实例化,并调用contextInitialized方法。
1. org.springframework.web.context.ContextLoaderListener类进行容器的初始化时,该类会被Web容器(如Tomcat)自动实例化,并调用contextInitialized方法。
public void contextInitialized(ServletContextEvent event) { this.contextLoader = this.createContextLoader(); if(this.contextLoader == null) { this.contextLoader = this; } this.contextLoader.initWebApplicationContext(event.getServletContext());}
2. initWebApplicationContext继承自父类ContextLoader,进入该方法后首先判断servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) 是否为空,查看WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE对应的源码可知其表示Spring的根容器,该句判断主要是确保web容器中只有一个Spring根容器。
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!"); } else { 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 { if(this.context == null) { this.context = this.createWebApplicationContext(servletContext); } if(this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext err = (ConfigurableWebApplicationContext)this.context; if(!err.isActive()) { if(err.getParent() == null) { ApplicationContext elapsedTime = this.loadParentContext(servletContext); err.setParent(elapsedTime); } this.configureAndRefreshWebApplicationContext(err, servletContext); } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader err1 = Thread.currentThread().getContextClassLoader(); if(err1 == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if(err1 != null) { currentContextPerThread.put(err1, 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 elapsedTime1 = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime1 + " ms"); } return this.context; } catch (RuntimeException var8) { logger.error("Context initialization failed", var8); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8); throw var8; } catch (Error var9) { logger.error("Context initialization failed", var9); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var9); throw var9; } }}
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE对应的源码,如下:
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
紧接着调用createWebApplicationContext(servletContext)方法,很显然这个方法是用来创建web容器的;
3.createWebApplicationContext首先调用determineContextClass方法,用来确定Context的具体实现类;
protected WebApplicationContext createWebApplicationContext(ServletContext sc) { Class contextClass = this.determineContextClass(sc); if(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } else { return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass); }}
4.determineContextClass方法根据web.xml初始化参数来确定Context的具体实现类
protected Class<?> determineContextClass(ServletContext servletContext) { String contextClassName = servletContext.getInitParameter("contextClass"); if(contextClassName != null) { try { return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); } catch (ClassNotFoundException var4) { throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", var4); } } else { contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try { return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); } catch (ClassNotFoundException var5) { throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", var5); } }}
5.当前类(ContextLoader)中,查看defaultStrategies.getProperty(WebApplicationContext.class.getName())获取的默认Context实现类信息,如下
static { try { ClassPathResource ex = new ClassPathResource("ContextLoader.properties", ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(ex); } catch (IOException var1) { throw new IllegalStateException("Could not load \'ContextLoader.properties\': " + var1.getMessage()); } currentContextPerThread = new ConcurrentHashMap(1);}
可知spring是通过ContextLoader.properties文件来找到相应的实现类信息,打开ContextLoader.properties文件,发现spring默认的Context实现类是org.springframework.web.context.support.XmlWebApplicationContext
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
6.回到initWebApplicationContext方法,在createWebApplicationContext方法后,会执行if(this.context instanceof ConfigurableWebApplicationContext)判断,由于Context默认返回类型为ConfigurableWebApplicationContext,由于此时尚未初始化,程序会进入loadParentContext这个方法,名字也很清楚明白,这个方法是用来加载父类发上下文对象。然后,执行configureAndRefreshWebApplicationContext方法,主要用于刷新上下文。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { String initParameter; if(ObjectUtils.identityToString(wac).equals(wac.getId())) { initParameter = sc.getInitParameter("contextId"); if(initParameter != null) { wac.setId(initParameter); } else if(sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { 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); initParameter = sc.getInitParameter("contextConfigLocation"); if(initParameter != null) { wac.setConfigLocation(initParameter); } this.customizeContext(sc, wac); wac.refresh();}
在该方法中:
①根据Context实现类的名称设置上下文的名称;
public static String identityToString(Object obj) { return obj == null?"":obj.getClass().getName() + "@" + getIdentityHexString(obj);}
②this.customizeContext(sc,wac)主要用于自定义初始化
③wac.refresh()加载xml配置,该方法用于设置代理工厂类、生成beanFactory、实例化类、向web容器注册beanFactory等等操作,其中根据web.xml文件中contextConfigLocation配置信息实例化类是重中之重。
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); try { this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var5) { this.destroyBeans(); this.cancelRefresh(var5); throw var5; } }}web.xml文件中contextConfigLocation的配置信息
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:applicationContext.xml </param-value></context-param>
1 0
- 由源码理解spring初始化过程
- Spring 初始化过程详细分析[源码](一)
- Spring 初始化过程详细分析 [源码] (二)
- Spring初始化过程源码分析(1)
- 【Spring mvc】Spring MVC源码分析——初始化过程
- 深入理解Spring系列之九:DispatcherServlet初始化源码分析
- 【Spring】IOC核心源码学习(二):容器初始化过程
- Spring MVC源码分析——初始化过程
- 【Spring】IOC核心源码学习(二):容器初始化过程
- 【Spring】IOC核心源码学习:容器初始化过程
- Spring MVC源码分析——初始化过程
- Spring MVC源码分析——初始化过程
- Spring MVC源码分析——初始化过程
- Spring MVC源码分析——初始化过程
- spring源码分析-web容器初始化过程解析1
- Spring IoC容器初始化过程(源码视角)
- spring源码学习 - 注解bean的初始化过程
- Spring Bean 初始化过程
- C# 类库读取app.config
- struts2项目启动报错com.opensymphony.xwork2.config.ConfigurationException: Unable to load configuration.
- lxml学习笔记
- PHP多线程扩展pthreads实例
- rocketmq介绍及安装过程
- 由源码理解spring初始化过程
- poj 3159
- cocos2d-x中截屏的方法、保存图片,以及使用截屏作为背景实例
- 226. Invert Binary Tree *
- 独立开发者的生存之道
- iOS Socket通信编程
- python abs() 函数
- Error: Configuration with name 'default' not found in Android Studio 解决
- jmeter连接Oracle数据库