工作至今,一直在使用spring,并且对spring的强大的功能无不折服,虽然一直使用,但对spring容器的启动流程却不知其所以然,最近花了点时间查阅了部分资料,配合源码对spring容器的启动仔细的了解一下,在此,记录一下整个过程,这里以spring-web项目的启动为基础进行分析。
在web项目中,首先会注意到web.xml这个文件,里面配置各种监听、过滤器,servlet等,spring容器的启动入口就在web.xml里进行配置:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
ContextLoaderListener:上下文加载监听器,spring容器的启动就自从这里开始,跟随代码到ContextLoaderListener类中,有这么一个方法
/**
* Initialize the root web application context.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
initWebApplicationContext方法,从方法名称上可以看出,这里开始初始化web容器了,跟随代码进入该方法:
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;
}
}
该方法的实现位于ContextLoaderListener的父类ContextLoader中,在此方法中我们重点可以看到这块代码:
if (this.context == null) {
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);
}
在该方法中我们重点关注一下determineContextClass(sc)这里的实现:
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);
}
}
}
这个方法的主要工作就是,获取初始化参数contextClass,如果我们在web.xml中配置了该参数,则使用ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());,即前面提到的上下文对象。本文中的实力项目中没有在web.xml中配置该参数,则会进入else处理逻辑,在这里我们可以看到有这么一句代码:
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
这里的defaultStrategies我们可以在该类的顶部静态块中看到它的初始化逻辑:
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
}
}
这里的意思很明确,就是加载默认的配置项,读取spring默认的上下文类,全文搜索一下这个DEFAULT_STRATEGIES_PATH文件,在spring-web包下的/resources/org/springframework/web/context目录下可以找到这个文件,里面的内容为:
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
这里就是配置了默认的WebApplicationContextd的类型为XmlWebApplicationContext
接下来回到determineContextClass方法中,后面就是使用ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());来加载这个上下文对象并且返回。
回到createWebApplicationContext方法继续往下走,
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);
首先判断指定的webApplicationContext是否是ConfigurableWebApplicationContext类型,如果不是则抛出异常终止容器启动,如果是则实例化该webApplicationContext对象,这里我们就是创建XmlWebApplicationContext对象,并返回到initWebApplicationContext方法中。到此整个spring容器的初始化就完成了,也就是容器启动完成了。但是,在上面提到的内容中,并没有涉及到spring各种bean的实例化和初始化,那么回过头来看看initWebApplicationContext方法中有这么几行代码:
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);
}
}
其中的configureAndRefreshWebApplicationContext(cwac, servletContext);进入方法详情查看一下:
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...
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);
}
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);
wac.refresh();
}
在这个方法里我们重点看一下customizeContext(sc, wac)和wac.refresh(),customizeContext(sc, wac)这里是初始化定制的容器,在此就不做深入,我们重点看一下wac.refresh()方法,了解过spring源码的同学对这个方法就比较熟悉了,因为它就是spring的各种bean创建的入口了,下面我们进入到方法里面看一下,在这里进入到实现类的的时候回出现让选择具体的实现类,如图:
这里我们进入AbstractApplicationContext的refresh(),该方法的主要内容如下:
@Override
public void 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) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
这个方法包含了spring启动的大部分操作
prepareRefresh()
包含了几个操作:
1-设置启动的时间戳
2-设置容器为未关闭状态
3-设置容器为活动状态
4-在上下文环境中初始化任何占位符属性源
5-在环境变量中验证必须的属性
6-初始化上下文事件容器(本质是一个LinkedHashSet)
obtainFreshBeanFactory()
获取BeanFactory,包含了两个操作:
1.refreshBeanFactory(),刷新beanFactory,该方法的具体实现在AbstractRefreshableApplicationContext中,如果已经存在了beanFactory,先销毁所有的单例bean,然后关闭beanFactory,接着就开始创建beanFactory,
定制beanFacotory属性(allowBeanDefinitionOverriding和allowCircularReferences),之后这开始加载bean定义-loadBeanDefinitions(beanFactory),加载bean定义这里就变得比较灵活了,不同的webApplocationContext都有自己的实现方式:
此处,我们来看XmlWebApplicationContext中的loadBeanDefinitions,因为默认的容器类型是XmlWebApplicationContext。跟踪代码,一直到XmlBeanDefinitionReader中的loadBeanDefinitions(EncodedResource encodedResource)方法中有这么一段代码:
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();
}
}
这里是resource就是我们在web.xml中配置的spring的相关的配置文件路径,通过doLoadBeanDefinitions(inputSource, encodedResource.getResource())来加载对应的配置文件,然后我们进入到doLoadBeanDefinitions方法去看一下:
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
主要功能代码就是这两行,其他的可以忽略,doLoadDocument从字面上理解就是去加载文本,这个文本就是我们的spring的相关xml文件,这里就不再继续深入了,总之,就是解析spring的xml文件返回一个document对象。
registerBeanDefinitions(doc, resource)方法则是吧document解析到beanDefinition中,具体的操作可以看一下DefaultBeanDefinitionDocumentReader中的doRegisterBeanDefinitions(Element root)方法,主要有4个重要的操作:
①创建委托者createDelegate(getReaderContext(), root, parent)
②处理xml数据的前置处理preProcessXml(root),类似于bean的前置处理,这个就是留给用户扩展的口子
③解析Document到beanDefinition中parseBeanDefinitions(root, this.delegate)
④处理xml数据的后置处理postProcessXml(root),类似于bean的后置处理,这个也是留给用户扩展的口子
再细看parseBeanDefinitions(root, this.delegate)的实现,这里就是典型的委派模式,跟踪代码到BeanDefinitionParserDelegate中的parseCustomElement(Element ele, @Nullable BeanDefinition containingBd):
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
从代码中可以看到,这里是根据namespaceUri来获取对应的配置处理器的,也就是说,如果用户自己创建了一个非spring内置的xml格式,需要自己定义对应的解析器来解析用户自定义的xml(当然,这里的Xml只是代表,不代表只能使用xml来进行配置,也可以通过其他格式的配置文件来进行配置,只要配合对应的解析器即可),把从配置从定义的beanName和beanDefinition存放在beanDefinitionMap(本质为ConcurrentHashMap:key为beanName,value为beanDefinition)中,loadBeanDefinition到这里就结束了
2.getBeanFactory(),获取beanFactory,这里的beanFactory是在loadBeanDefinition中创建的,这里只是获取一下,获取到之后就返回beanFactory对象
prepareBeanFactory(ConfigurableListableBeanFactory beanFactory)
prepareBeanFactory里主要包含几个内容:
①设置beanFactory的加载器:beanFactory.setBeanClassLoader(getClassLoader())
②设置beanFactory的表达式语言处理器:beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()))
③为beanFactory增加了一个默认的属性管理器:beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()))
④添加一个处理aware相关接口的beanPostProcessor扩展,这里主要是使用BeanPostProcessor的postProcessBeforeInitialization()和 postProcessAfterInitialization来做增强,在Bean初始化前和后提供更多的可操作性:beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))
⑤忽略几个接口的自动装配:默认情况下只有BeanFactoryAware会被忽略,这里添加了EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware这个几个接口被忽略
⑥设置几个接口的自动装配规则:如果为BeanFactory类型,则注入beanFactory,如果是ResourceLoader、ApplicationEventPublisher、ApplicationContext,则注入当前对象
⑦注册后置处理器ApplicationListenerDetector,检测是否有事件监听以及判断是否有对编译时AspectJ的支持,这些都是通过后置处理器来完成的,最后主要是给BeanFactory注册一些能通用的组件
⑧判断是否包含了loadTimeWeaver,有则注册对应的后置处理,并这只临时的类加载器
⑨判断是否包含environment、systemProperties、systemEnvironment,如果存在则进行单例注册
postProcessBeanFactory(beanFactory)
①添加ServletContextAwareProcessor子类的后置处理扩展
②忽略ServletContextAware、ServletConfigAware的自动装配
③注册web相关作用于bean:request、session、application,添加ServletRequest、ServletResponse、HttpSession、WebRequest的自动装配规则
④在web容器启动过程中注册web相关环境bean
invokeBeanFactoryPostProcessors(beanFactory)
调用上下文中注册为bean的工厂处理器。
registerBeanPostProcessors(beanFactory)
实例化和调用所有已注册的BeanPostProcessor bean
如果给出显式顺序,则按顺序执行
必须在应用程序bean的任何实例化之前调用
其中的详细流程包含以下几步:
获取所有类型为BeanPostProcessor的bean的name的数组
添加BeanPostProcessorChecker子类的后置处理器
分离实现了PriorityOrdered、Ordered和其他接口的BeanPostProcessors
注册实现了PriorityOrdered的BeanPostProcessors
注册实现了Ordered的BeanPostProcessors
注册常规的BeanPostProcessors
最后重新排序,然后重新注册所有的BeanPostProcessors
将检测内部bean的后处理器重新注册为ApplicationListeners(监听),并将其移动到处理器链的末尾
initMessageSource()
初始化MessageSource组件,主要为做国际化功能;消息绑定,消息解析做准备,这里就不深入了
initApplicationEventMulticaster()
初始化应用事件广播,这里我们可以这样理解,我们定制一个spring的事件监听,如实现ApplicationListener<ApplicationStartedEvent>,需要再应用启动完成后获得通知并进行我们自己的相关逻辑处理,这个时候的事件是如何通知过来的呢?那么就是在initApplicationEventMulticaster方法初始化这个事件广播,我们来看一下initApplicationEventMulticaster这个方法:
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
首先会查看当前beanFactory中是否包含了名为applicationEventMulticaster的bean,如果有则通过名称beanFactory中获取这个bean,赋给当前容器的applicationEventMulticaster对象,如果没有,就需要去实例化一个该对象,我们可以进入到SimpleApplicationEventMulticaster类里面进行查看,在这个类中我们重点看以下方法:
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
当我们初始化了名为applicationEventMulticaster的事件广播后,我们很好理解的是,之后有一旦有新的事件,就会调用multicastEvent方法来广播事件,然而这个方法的实质就是调用对应的listener,即spring定义的一系列时间监听,listener.onApplicationEvent(event)这句代码就很好的印证了这一点,下面是我测试时实现的一个事件监听:
public class ApplicationStartedEventListener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
log.info("in my ApplicationStartedEvent");
}
}
listener.onApplicationEvent(event)实际上调用的就是我们自定义的这部分代码,完成了我们想要的效果。
当然,在这里只是做了应用事件的广播初始化,还需要把对应的监听注册到广播之后才能发挥它的强大功能,至于注册动作,这个留到下面去分析。
onRefresh()
从各个实现类来看,该方法主要是初始化主题源,具体使用我也没有接触过,暂不做赘述
registerListeners()
官方注释:检查侦听器bean并注册它们
进入方法的实现可以看到:
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
遍历所的监听,然后getApplicationEventMulticaster(),获取到applicationEventMulticaster,这里就是上面初始化的那个事件广播,通过addApplicationListener(listener),让广播来通知对应的监听,这就是上面未详细描述的一个事件监听注册的实现,如果有早期事件需要广播,这里就指定getApplicationEventMulticaster().multicastEvent(earlyEvent)来广播事件。
finishBeanFactoryInitialization(beanFactory)
官方注释:实例化所有剩余的(非懒加载)单例
这里是整个容器最核心的部分,因为这里包含了大部分bean的创建,依赖注入的实现逻辑,动态代理bean都在这里创建。下面开始进入这个方法。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
beanFactory.setTempClassLoader(null);
beanFactory.freezeConfiguration();
beanFactory.preInstantiateSingletons();
}
首先关注一下beanFactory.freezeConfiguration(),这个方法在代码中有这一段注释
"Allow for caching all bean definition metadata, not expecting further changes."翻译过来就是允许缓存所有bean定义的元数据,不考虑改变,也就是冻结配置,就算此事元数据发生了改变也不参考。此处冻结了配置,也保证了后面取用beanDefiniton来创建Bean的一致性,不会再创建bean的时候因为元数据发生了改变而造成其他问题。接下来进入重点关注的方法beanFactory.preInstantiateSingletons()
preInstantiateSingletons()的方法实现位于DefaultListableBeanFactory中,之前在spring-beans重点类说明一文中有提到,DefaultListableBeanFactory乃ioc容器的始祖,这个类就是BeanFactory的具体实现,是整个spring的bean的生产车间。
preInstantiateSingletons方法主要包含两部分功能
①实例化bean
②为所有需要适用的bean执行实例化后的回调
我们先来看看是如何实例化bean的:
要创建bean就必须得拿到对应Bean的元数据,这个时候我们首先会想到在执行obtainFreshBeanFactory()方法中说到的beanDefinition,所以首先得拿到这个beanDefinition,调用方法:
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
从beanDefiniton中可以得知,该bean是否为抽象、是否是单例、是否为是懒加载(延迟加载),如果不是抽象类,不是懒加载,是单例的情况下,在进行判断,判断bean是否为FactoryBean(FactoryBean因为它是一种Factory类型的bean,所以在获取的时候要通过&+beanName才能获取对应的FactoryBean),然后处理对需要优先创建FactoryBean进行优先创建。之后的逻辑就是创建普通的bean了,进入getBean方法查看,跟踪代码一直到doGetBean方法,该方法位于AbstractBeanFactory类中。spring所有类中,但凡是以doXx命名的方法就是真正做事的方法了,doGetBean说明这个方法里在进行bean的创建了。我们来看一下这个方法中的这段代码:
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
}
这段代码的意思是获取当前bean的依赖mbd.getDependsOn(),如果有依赖其他的bean,就判断当前的bean和依赖的bean有没有循环依赖的关系,如果有则抛出异常,如果没有就去注册依赖关系,然后创建依赖的bean,这里的getBean(dep)就是一个递归调用,循环创建bean,这里能很好的体现出依赖注入了。接下来我们继续看到这段代码:
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
注意这里的ObjectFactory,等会儿在后面还会用到,得到单例实例后进入到getObjectForBeanInstance方法中一直跟踪代码到FactoryBeanRegistrySupport类中的doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)这个方法中:
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
}
这里最终返回的对象名称叫object,从代码中我们可以看到,其实最终返回的都是factory.getObject()获得的对象,这个factory就是刚刚在方法中传进来的shareInstance实例,这个时候实际上调用的是实例的getObject()方法即:
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
看到这里的creatBean我们就放心了,它最终还是回到了创建Bean的正道当中来了,createBean的具体实现在AbstractAutowireCapableBeanFactory类中,跟踪代码,进入到doCreateBean方法,然后再进入createBeanInstance方法,这个方法里提供了两种创建bean实例的方式,
一种是autowireConstructor(beanName, mbd, null, null):这个方法作用是获取被包装后的bean,包装后的对象是BeanWrapper对象,这个对象的实现类是BeanWrapperImpl。其中包含被封装后待处理的bean,和设置bean属性的属性编辑器
另一种是instantiateBean(beanName, mbd):即加载实例化bean
先来看容易理解一点的instantiateBean,具体的实现代码:
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
这里就判断了是否存在override的方法,如果不存在则获取构造器,然后通过构造器来.newInstance(args),获得bean的实例对象
如果存在方法的覆写,则必须生成CGLIB子类,这里我们就能感受到,基于cglib的动态代理类是如何生成的了,具体的生成方式我们可以到CglibSubclassingInstantiationStrategy类中查看,具体创建代理类的方法:
private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanDefinition.getBeanClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
if (this.owner instanceof ConfigurableBeanFactory) {
ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
}
enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
enhancer.setCallbackTypes(CALLBACK_TYPES);
return enhancer.createClass();
}
这里就不继续深入下去了,有兴趣的朋友可以专门研究一下。
不管是哪一种方式来创建bean的实例,最终返回一个beanInstance包装过后的包装对象BeanWrapper,随即调用populateBean方法从beanWrapper中获取beanDefinition填充bean实例中的属性,然后还会再调用initializeBean(beanName, exposedObject, mbd),这个方法就主要做一些扩展的功能了:
①如果bean实现了Aware接口,就可以执行一些增强的方法,如:setBeanName,setBeanClassLoader,setBeanFactory
②执行bean初始化的前置处理(扩展)
③执行bean的初始化方法,在这里面还会执行属性设置的后置处理(扩展)afterPropertiesSet()
④执行bean初始化完成后的后置处理(扩展)
到此,bean的创建流程就完成了,最后为当前bean的销毁提供策略和实现 registerDisposableBeanIfNecessary,整个bean创建流程结束。
finishRefresh()
官方注释:发布相应的事件
主要操作:
①初始化此上下文的生命周期处理器
②getLifecycleProcessor().onRefresh();生命周期处理器处理器onRefresh方法看到其实是执行的DefaultLifecycleProcessor中的startBeans,就是启动所有的bean,在启动完成后则把DefaultLifecycleProcessor中的running设置为true表示应用启动了
③发布ContextRefreshedEvent类型的事件
④最后会检查一个配置spring.liveBeansView.mbeanDomain是否存在,有就会创建一个MBeanServer
resetCommonCaches()
重置常用的缓存,这里应该跟上面提到的beanFactory.freezeConfiguration()对应起来了,这里因为bean已经创建完成,不会再使用到bean的相关元数据了,可以刷新一下对应缓存,也不会印象bean的正常工作。
end
至此,整个spring-web容器就启动完成了,整个流程的分析也到此结束,可能其中有理解得不正确或遗漏的地方,我也将继续探究,并实时作出修改。
总结
spring经历的这么年的发展,其功能的强大不可言表,我也会在以后的学习中进一步去探究跟多的功能原理,也建议朋友们去深入理解一下,从中肯定能获益良多!
最后附上一个简单的容器启动流程图: