上面一篇文章提到,在Servlet初始化的时候,获取属性后调用initServletBean,这个方法会initWebApplicationContext,这是DispatcherServlet对后面的处理做了很多的预先准备工作,我们一起来看看它到底做了什么事情。
流程
- 先上代码,初始化和发布WebApplicationContext到servlet中,对于真正的创建操作是交给子类的createWebApplicationContext来实现的。
/**
* Initialize and publish the WebApplicationContext for this servlet.
* <p>Delegates to {@link #createWebApplicationContext} for actual creation
* of the context. Can be overridden in subclasses.
* @return the WebApplicationContext instance
* @see #FrameworkServlet(WebApplicationContext)
* @see #setContextClass
* @see #setContextConfigLocation
*/
protected WebApplicationContext initWebApplicationContext() {
// 获取WebApplicationContext,但是首次取得的值一般为null
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
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 -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
// 在当前的servlet中,没有对应的context实例时候,创建一个。
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
- 首先获取WebApplicationContext,一般获取的值为null
- 然后试着findWebApplicationContext(),这一步主要看其父类的是否已经注册了对应的context. 父类的context首次也为null
- 如果WebApplicationContext还未找到,那么尝试创建一个WebApplicationContext
-
上一步对于最初的操作,获得的WebapplicationContext都是null的,因此需要创建一个WebapplicationContext.
为当前的Servlet实例化WebApplicationContext
/**
* Instantiate the WebApplicationContext for this servlet, either a default
* {@link org.springframework.web.context.support.XmlWebApplicationContext}
* or a {@link #setContextClass custom context class}, if set.
* <p>This implementation expects custom contexts to implement the
* {@link org.springframework.web.context.ConfigurableWebApplicationContext}
* interface. Can be overridden in subclasses.
* <p>Do not forget to register this servlet instance as application listener on the
* created context (for triggering its {@link #onRefresh callback}, and to call
* {@link org.springframework.context.ConfigurableApplicationContext#refresh()}
* before returning the context instance.
* @param parent the parent ApplicationContext to use, or {@code null} if none
* @return the WebApplicationContext for this servlet
* @see org.springframework.web.context.support.XmlWebApplicationContext
*/
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
//获取默认的getContextClass,默认的contextClass为XmlWebApplicationContext.class,可以从源码中看到
Class<?> contextClass = getContextClass();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet with name '" + getServletName() +
"' will try to create custom WebApplicationContext context of class '" +
contextClass.getName() + "'" + ", using parent context [" + parent + "]");
}
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
// 使用BeanUtils实例化ApplicationContext类。
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
configureAndRefreshWebApplicationContext(wac);
return wac;
}
- 首先获取默认的要实例化的ApplicationContxt类,默认的为XmlWebApplicationContext
- 使用BeanUtil实例化ApplicationContxt的类,BeanUtils是个很有用的方法,可以多看下
- ApplicationContxt被实例化之后,做一些配置,设置当前的Environment,设置父类(如果有的话),获取contextLocation的位置(web.xml中可以设置,当然也有默认值)
- 配置然后刷新WebApplicationContex类
- 对WebApplicationContext类做配置和刷新。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
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
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// 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(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();
}
- 首先生成WebApplicationContext的id,用于后面加载Spring-MVC的配置文件
- 在WebApplicationContext中设置容器的ServletContext,ServiletConfig,并设置默认的命名空间
- 添加ApplicationContext的监听器,监听ContextRefresh事件
- 初始化环境属性
- postProcessWebApplicationContext,初始化WebApplicationContext之后做的事情,默认为空,后面自行扩展的时候可以覆盖
- applyInitializers, 后面可以多了解下,初始器
- 刷新WebApplicationContext.
- WebApplicationContext的刷新操作。
- 使用synchronized保证线程安全
- 下面每一个方法都包含一些具体的操作
@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.
// 告诉子类刷新内部的bean factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 准备beanfactory来使用
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();
}
}
}
- 仔细看一下refresh中的每一个大方法,首先prepareRefresh,可以看到prepareRefresh,确实只做一些准备性的工作,没有实质性的处理。
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
- obtainFreshBeanFactory()告诉子类刷新内部的beanfactory, 默认的beanFactory是DefaultListableBeanFactory。
obtainFreshBeanFactory中刷新BeanFactory的操作是交给其子类来实现的。AbstractRefreshableApplicationContext是真正做了刷新的操作,并且加载了beanDefinitions.
关于如何loadBeandefenition,后面可以再深入去看
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//加载bean的定义
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
- 让beanFactory准备好使用context. 可以看到beanFactory做了很多的配置
- 设置ClasLoader,SPEL,PropertyEditorRegistrar
- 添加ApplicationContextAware,用于让bean设置ApplicationContextde .等等
- 解析依赖关系ResolvableDependency相关的内容
- 一些需要早期的bean处理
- 注册一些系统默认的bean,如Environment,SystemProperties等等
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
- beanFactory处理之后的处理,这一步可以理解为上一步的后续处理,和上一步类似都是对beanFactory的处理
/**
* Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
*/
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
- 激发上下文中创建bean的后续操作,这个内部包含了很多内容,大部分的操作在PostProcessorRegistrationDelegate类里面的invokeBeanFactoryPostProcessors中,一个方法写了100多行,内容很多,这里就粘贴出来了,东西太多。记得PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
包括下一步的registerBeanPostProcessors操作也是由PostProcessorRegistrationDelegate来完成的。这个类看来也挺重要,不过它的访问权限是默认的,看来Spring不想暴露出来给我们用。
PostProcessorRegistrationDelegate
-
initMessageSource,操作,进入里面看到这些操作都是围绕着BeanFactory在进行,beanFactory设置DelegatingMessageSource。
-
设置Application广播发出器,可以看到内部仍然是对beanFactory设置一个默认的类
-
onRefresh方法其实现类基本上都是在初始化主题,GenericWebApplicationContext与AbstractRefreshableWebApplicationContext都是如此
- 注册监听器,看截图可以看出其主要在上面的事件caster中添加应用事件的bean
- 看一下最后的操作吧,结束刷新操作,发布已经刷新后的事件。
/**
* Finish the refresh of this context, invoking the LifecycleProcessor's
* onRefresh() method and publishing the
* {@link org.springframework.context.event.ContextRefreshedEvent}.
*/
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
- 重置Spring中的cache
/**
* Reset Spring's common core caches, in particular the {@link ReflectionUtils},
* {@link ResolvableType} and {@link CachedIntrospectionResults} caches.
* @since 4.2
* @see ReflectionUtils#clearCache()
* @see ResolvableType#clearCache()
* @see CachedIntrospectionResults#clearClassLoader(ClassLoader)
*/
protected void resetCommonCaches() {
ReflectionUtils.clearCache();
ResolvableType.clearCache();
CachedIntrospectionResults.clearClassLoader(getClassLoader());
}
回顾
感觉Spring-mvc中的initWebApplicationContext做了很多的事情,先抓住大方向,细节很多,回顾一下这次看到了那些内容。
从initServletBean开始,然后initWebApplicationContext,初始情况下ApplicationContext是为null的,我们需要创建默认的ApplicationContext,Spring-mvc中默认的ApplicationContext是XmlWebApplicationContext。
使用反射创建XmlWebApplicationContext之后,将XmlWebApplicationContext作为参数传递到配置和刷新XmlWebApplicationContext的方法中,接下来的操作,集中在对XmlWebApplicationContext的配置中。
配置Enviriment,ServletConfig,初始属性,命名空间,过滤器等等。最后调用XmlWebApplicationContext的refresh操作。
refresh操作中主要围绕bean相关的内容在操作,创建beanFactory,然后对beanFactory做配置,同时加载bean,bean的生命周期等等操作。然后注册bean以外的内容,配置主题,事件,消息等等,最后结束刷新,完成整个bean的生命周期。
最后
这里只是initWebApplicationContext,感觉bean的生命周期处理也是在这一步内部配置的,后面有关bean的生命周期,可以在内部仔细看一下。
initWebApplicationContext中,涉及到很多的类,很多默认的类,多读几遍,也许将来自己造轮子的某一天可以参考Spring的设计。
本人才疏学浅,阅读Spring源码的过程,做了一些记录,供参考作用,如果感兴趣,想后续交流欢迎一起探讨。