简介
Spring是一个轻量级的AOP和IOC框架。主要用来简化Java应用程序的开发,降低组件和组件之间的耦合性。大约有20个模块,主要由七个模块组成,分别是Spring Core、Spring Context、Spring AOP、Spring Dao、Spring ORM、Spring Web和Spring MVC。 其中,Core和Beans模块是框架的基础部分,提供IOC和依赖注入。 Spring Ioc就是对java反射及读取xml文件的使用的封装 本文将简要介绍和分析Spring项目启动的流程,以及启动过程中ApplicationContext如何实现IOC控制反转。
SSM开发模式中容器启动流程
web项目中容器启动的流程,起点是web.xml中配置的ContextLoaderListener监听器
调用流程图
流程解析
Tomcat服务器启动时会读取项目中web.xml中的配置项来生成ServletContext ,ServletContext表示的是一整个应用,其中囊括应用的所有内容,ContextLoaderListener 是ServletContextListener接口的实现类,它会时刻监听ServletContext的动作,包括创建和销毁 ServletContext创建的时候会触发其contextInitialized()初始化方法的执行。
ContextLoaderListener
package org. springframework. web. context ;
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener ( ) {
}
public ContextLoaderListener ( WebApplicationContext context) {
super ( context) ;
}
@Override
public void contextInitialized ( ServletContextEvent event) {
initWebApplicationContext ( event. getServletContext ( ) ) ;
}
@Override
public void contextDestroyed ( ServletContextEvent event) {
closeWebApplicationContext ( event. getServletContext ( ) ) ;
ContextCleanupListener . cleanupAttributes ( event. getServletContext ( ) ) ;
}
}
ContextLoader
在这段源码中主要是概述Spring容器的创建和初始化,分别由两个方法实现:createWebApplicationContext方法和configureAndRefreshWebApplicationContext方法。
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!" ) ;
}
servletContext. log ( "Initializing Spring root WebApplicationContext" ) ;
Log logger = LogFactory . getLog ( ContextLoader . class ) ;
if ( logger. isInfoEnabled ( ) ) {
logger. info ( "Root WebApplicationContext: initialization started" ) ;
}
long startTime = System . currentTimeMillis ( ) ;
try {
if ( this . context == null ) {
this . context = createWebApplicationContext ( servletContext) ;
}
if ( this . context instanceof ConfigurableWebApplicationContext ) {
ConfigurableWebApplicationContext cwac = ( ConfigurableWebApplicationContext ) this . context;
if ( ! cwac. isActive ( ) ) {
if ( cwac. getParent ( ) == null ) {
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. isInfoEnabled ( ) ) {
long elapsedTime = System . currentTimeMillis ( ) - startTime;
logger. info ( "Root WebApplicationContext initialized in " + elapsedTime + " ms" ) ;
}
return this . context;
}
catch ( RuntimeException | Error ex) {
logger. error ( "Context initialization failed" , ex) ;
servletContext. setAttribute ( WebApplicationContext . ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex) ;
throw ex;
}
}
创建Spring容器实例 this.context = createWebApplicationContext(servletContext);
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) ;
}
重点操作:配置并刷新容器 从这里开始进入IOC。configureAndRefreshWebApplicationContext(cwac, servletContext);
protected void configureAndRefreshWebApplicationContext ( ConfigurableWebApplicationContext wac, ServletContext sc) {
if ( ObjectUtils . identityToString ( wac) . equals ( wac. getId ( ) ) ) {
String idParam = sc. getInitParameter ( CONTEXT_ID_PARAM) ;
if ( idParam != null ) {
wac. setId ( idParam) ;
}
else {
wac. setId ( ConfigurableWebApplicationContext . APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils . getDisplayString ( sc. getContextPath ( ) ) ) ;
}
}
wac. setServletContext ( sc) ;
String configLocationParam = sc. getInitParameter ( CONFIG_LOCATION_PARAM) ;
if ( configLocationParam != null ) {
wac. setConfigLocation ( configLocationParam) ;
}
ConfigurableEnvironment env = wac. getEnvironment ( ) ;
if ( env instanceof ConfigurableWebEnvironment ) {
( ( ConfigurableWebEnvironment ) env) . initPropertySources ( sc, null ) ;
}
customizeContext ( sc, wac) ;
wac. refresh ( ) ;
}
Spring IOC实现
查看wac.refresh()的使用,调用的是AbstractApplicationContext类下的refresh方法实现
package org. springframework. context. support ;
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
. . . . . . 省略无数代码
@Override
public void refresh ( ) throws BeansException , IllegalStateException {
synchronized ( this . startupShutdownMonitor) {
prepareRefresh ( ) ;
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory ( )
prepareBeanFactory ( beanFactory) ;
try {
postProcessBeanFactory ( beanFactory) ;
invokeBeanFactoryPostProcessors ( beanFactory) ;
registerBeanPostProcessors ( beanFactory) ;
initMessageSource ( ) ;
initApplicationEventMulticaster ( ) ;
onRefresh ( ) ;
registerListeners ( ) ;
finishBeanFactoryInitialization ( beanFactory) ;
finishRefresh ( ) ;
}
catch ( BeansException ex) {
if ( logger. isWarnEnabled ( ) ) {
logger. warn ( "Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex) ;
}
destroyBeans ( ) ;
cancelRefresh ( ex) ;
throw ex;
}
finally {
resetCommonCaches ( ) ;
}
}
}
}
上述步骤二:obtainFreshBeanFactory()
初始化BeanFactory,并进行XML文件读取。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory ( ) {
refreshBeanFactory ( ) ;
return getBeanFactory ( ) ;
}
refreshBeanFactory()刷新BeanFactory
此处refreshBeanFactory()获取的是AbstractApplicationContext子类AbstractRefreshableApplicationContext的refreshBeanFactory方法。
@Override
protected final void refreshBeanFactory ( ) throws BeansException {
if ( hasBeanFactory ( ) ) {
destroyBeans ( ) ;
closeBeanFactory ( ) ;
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory ( ) ;
beanFactory. setSerializationId ( getId ( ) ) ;
customizeBeanFactory ( beanFactory) ;
loadBeanDefinitions ( beanFactory) ;
this . beanFactory = beanFactory;
}
catch ( IOException ex) {
throw new ApplicationContextException ( "I/O error parsing bean definition source for " + getDisplayName ( ) , ex) ;
}
}
查看上述步骤四:进行XML文件读取及解析
此处loadBeanDefinitions(beanFactory)获取的是AbstractRefreshableApplicationContext子类AbstractRefreshableConfigApplicationContext的子类AbstractRefreshableWebApplicationContext的子类XmlWebApplicationContext的loadBeanDefinitions方法
package org. springframework. web. context. support ;
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
@Override
protected void loadBeanDefinitions ( DefaultListableBeanFactory beanFactory) throws BeansException , IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader ( beanFactory) ;
beanDefinitionReader. setEnvironment ( getEnvironment ( ) ) ;
beanDefinitionReader. setResourceLoader ( this ) ;
beanDefinitionReader. setEntityResolver ( new ResourceEntityResolver ( this ) ) ;
initBeanDefinitionReader ( beanDefinitionReader) ;
loadBeanDefinitions ( beanDefinitionReader) ;
}
}
loadBeanDefinitions(beanDefinitionReader)
此处loadBeanDefinitions(beanDefinitionReader)在当前类中调用的是AbstractBeanDefinitionReaderr类的loadBeanDefinitions方法,而AbstractBeanDefinitionReaderr调用的是BeanDefinitionReader的实现类AbstractBeanDefinitionReader下的实现类XmlBeanDefinitionReader的loadBeanDefinitions方法
package org. windframework. beans. factory. xml ;
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
@Override
public int loadBeanDefinitions ( Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions ( new EncodedResource ( resource) ) ;
}
public int loadBeanDefinitions ( EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert . notNull ( encodedResource, "EncodedResource must not be null" ) ;
if ( logger. isTraceEnabled ( ) ) {
logger. trace ( "Loading XML bean definitions from " + encodedResource) ;
}
Set < EncodedResource > currentResources = this . resourcesCurrentlyBeingLoaded. get ( ) ;
if ( currentResources == null ) {
currentResources = new HashSet < > ( 4 ) ;
this . resourcesCurrentlyBeingLoaded. set ( currentResources) ;
}
if ( ! currentResources. add ( encodedResource) ) {
throw new BeanDefinitionStoreException (
"Detected cyclic loading of " + encodedResource + " - check your import definitions!" ) ;
}
try {
InputStream inputStream = encodedResource. getResource ( ) . getInputStream ( ) ;
try {
InputSource inputSource = new InputSource ( inputStream) ;
if ( encodedResource. getEncoding ( ) != null ) {
inputSource. setEncoding ( encodedResource. getEncoding ( ) ) ;
}
return doLoadBeanDefinitions ( inputSource, encodedResource. getResource ( ) ) ;
} finally {
inputStream. close ( ) ;
}
} catch ( IOException ex) {
throw new BeanDefinitionStoreException (
"IOException parsing XML document from " + encodedResource. getResource ( ) , ex) ;
} finally {
currentResources. remove ( encodedResource) ;
if ( currentResources. isEmpty ( ) ) {
this . resourcesCurrentlyBeingLoaded. remove ( ) ;
}
}
}
protected int doLoadBeanDefinitions ( InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument ( inputSource, resource) ;
int count = registerBeanDefinitions ( doc, resource) ;
if ( logger. isDebugEnabled ( ) ) {
logger. debug ( "Loaded " + count + " bean definitions from " + resource) ;
}
return count;
} catch ( BeanDefinitionStoreException ex) {
throw ex;
} catch ( SAXParseException ex) {
throw new XmlBeanDefinitionStoreException ( resource. getDescription ( ) ,
"Line " + ex. getLineNumber ( ) + " in XML document from " + resource + " is invalid" , ex) ;
} catch ( SAXException ex) {
throw new XmlBeanDefinitionStoreException ( resource. getDescription ( ) ,
"XML document from " + resource + " is invalid" , ex) ;
} catch ( ParserConfigurationException ex) {
throw new BeanDefinitionStoreException ( resource. getDescription ( ) ,
"Parser configuration exception parsing XML from " + resource, ex) ;
} catch ( IOException ex) {
throw new BeanDefinitionStoreException ( resource. getDescription ( ) ,
"IOException parsing XML document from " + resource, ex) ;
} catch ( Throwable ex) {
throw new BeanDefinitionStoreException ( resource. getDescription ( ) ,
"Unexpected exception parsing XML document from " + resource, ex) ;
}
}
public int registerBeanDefinitions ( Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader ( ) ;
int countBefore = getRegistry ( ) . getBeanDefinitionCount ( ) ;
documentReader. registerBeanDefinitions ( doc, createReaderContext ( resource) ) ;
return getRegistry ( ) . getBeanDefinitionCount ( ) - countBefore;
}
}
核心逻辑 registerBeanDefinitions(doc, createReaderContext(resource))
registerBeanDefinitions(doc, createReaderContext(resource))调用的是实现类DefaultBeanDefinitionDocumentReader的 registerBeanDefinitions方法
package org. windframework. beans. factory. xml ;
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
@Override
public void registerBeanDefinitions ( Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException {
this . readerContext = readerContext;
doRegisterBeanDefinitions ( doc. getDocumentElement ( ) ) ;
}
@SuppressWarnings ( "deprecation" )
protected void doRegisterBeanDefinitions ( Element root) {
BeanDefinitionParserDelegate parent = this . delegate;
this . delegate = createDelegate ( getReaderContext ( ) , root, parent) ;
if ( this . delegate. isDefaultNamespace ( root) ) {
String profileSpec = root. getAttribute ( PROFILE_ATTRIBUTE) ;
if ( StringUtils . hasText ( profileSpec) ) {
String [ ] specifiedProfiles = StringUtils . tokenizeToStringArray (
profileSpec, BeanDefinitionParserDelegate . MULTI_VALUE_ATTRIBUTE_DELIMITERS) ;
if ( ! getReaderContext ( ) . getEnvironment ( ) . acceptsProfiles ( specifiedProfiles) ) {
if ( logger. isDebugEnabled ( ) ) {
logger. debug ( "Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext ( ) . getResource ( ) ) ;
}
return ;
}
}
}
preProcessXml ( root) ;
parseBeanDefinitions ( root, this . delegate) ;
postProcessXml ( root) ;
this . delegate = parent;
}
}
进行XML的读取
package org. windframework. beans. factory. xml ;
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
protected void parseBeanDefinitions ( Element root, BeanDefinitionParserDelegate delegate) {
if ( delegate. isDefaultNamespace ( root) ) {
NodeList nl = root. getChildNodes ( ) ;
for ( int i = 0 ; i < nl. getLength ( ) ; i++ ) {
Node node = nl. item ( i) ;
if ( node instanceof Element ) {
Element ele = ( Element ) node;
if ( delegate. isDefaultNamespace ( ele) ) {
parseDefaultElement ( ele, delegate) ;
}
else {
delegate. parseCustomElement ( ele) ;
}
}
}
}
else {
delegate. parseCustomElement ( root) ;
}
}
private void parseDefaultElement ( Element ele, BeanDefinitionParserDelegate delegate) {
if ( delegate. nodeNameEquals ( ele, IMPORT_ELEMENT) ) {
importBeanDefinitionResource ( ele) ;
}
else if ( delegate. nodeNameEquals ( ele, ALIAS_ELEMENT) ) {
processAliasRegistration ( ele) ;
}
else if ( delegate. nodeNameEquals ( ele, BEAN_ELEMENT) ) {
processBeanDefinition ( ele, delegate) ;
}
else if ( delegate. nodeNameEquals ( ele, NESTED_BEANS_ELEMENT) ) {
doRegisterBeanDefinitions ( ele) ;
}
}
}
对bean标签的解析最复杂也最重要,因此从此开始分析
package org. windframework. beans. factory. xml ;
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
protected void processBeanDefinition ( Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate. parseBeanDefinitionElement ( ele) ;
if ( bdHolder != null ) {
bdHolder = delegate. decorateBeanDefinitionIfRequired ( ele, bdHolder) ;
try {
BeanDefinitionReaderUtils . registerBeanDefinition ( bdHolder, getReaderContext ( ) . getRegistry ( ) ) ;
}
catch ( BeanDefinitionStoreException ex) {
getReaderContext ( ) . error ( "Failed to register bean definition with name '" +
bdHolder. getBeanName ( ) + "'" , ele, ex) ;
}
getReaderContext ( ) . fireComponentRegistered ( new BeanComponentDefinition ( bdHolder) ) ;
}
}
}