Spring ApplicationContext上下文核心容器深入探究
赵韩兵先生 人气:0Spring 容器核心可归纳为两个类: BeanFactory 和 ApplicationContext,ApplicationContext 继承自 BeanFactory ,其不仅包含 BeanFactory 所有功能,还扩展了容器功能。ApplicationContext 核心其实是 refresh 方法,容器一系列功能都在该方法中实现,如:注册 Bean、注入 Bean 等。
整体流程
refresh 方法定义在 ConfigurableApplicationContext 接口中,被 AbstractApplicationContext 抽象类实现,该方法由十几个子方法组成,这些子方法各司其职完成容器的初始化。
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable { ...... //加载或刷新配置的持久表示形式, //可能是XML文件、属性文件或关系数据库模式。 //由于这是一个启动方法,它应该销毁已经创建的单例 //如果失败,则避免悬而未决的资源。换句话说,在调用该方法之后,要么全部实例化,要么根本不实例化。 //如果无法初始化bean工厂,则抛出BeanException异常,抛出IllegalStateException异常 //如果已初始化且不支持多次刷新尝试 void refresh() throws BeansException, IllegalStateException; ...... }
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { ...... @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备此上下文以进行刷新 prepareRefresh(); // 告诉子类刷新内部bean工厂 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 准备bean工厂,以便在此上下文中使用 prepareBeanFactory(beanFactory); try { // 允许在上下文子类中对bean工厂进行后处理 postProcessBeanFactory(beanFactory); // 调用在上下文中注册为bean的工厂处理器 invokeBeanFactoryPostProcessors(beanFactory); // 注册拦截bean创建的bean处理器 registerBeanPostProcessors(beanFactory); // 为此上下文初始化消息源。 initMessageSource(); // 为此上下文初始化事件多播 initApplicationEventMulticaster(); // 初始化特定上下文子类中的其他特殊bean onRefresh(); // 检查侦听器bean并注册它们 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 { // 重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据。。。 resetCommonCaches(); } } } ...... }
在spring中AbstractApplicationContext的实现类通过调用父类的方法完成容器的初始化,下文以ClassPathXmlApplicationContext为例来追踪容器的创建流程。
public class contextText { ApplicationContext context = new ClassPathXmlApplicationContext("spring-bean.xml"); }
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { ...... public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } ...... }
refresh 方法中,前四个子方法主要进行上下文准备工作。
prepareRefresh
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 初始化上下文环境,就是记录下容器的启动时间、活动状态等 prepareRefresh(); ... } }
public abstract class AbstractApplicationContext { ... private long startupDate; private final AtomicBoolean active = new AtomicBoolean(); private final AtomicBoolean closed = new AtomicBoolean(); private Set<ApplicationEvent> earlyApplicationEvents; ... protected void prepareRefresh() { // 记录此上下文开始时的系统时间(以毫秒为单位) this.startupDate = System.currentTimeMillis(); // 记录此上下文是否已关闭,这里设置为未关闭 this.closed.set(false); // 记录此上下文是否处于活动状态,这里设置为活动状态 this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // 这也是交由子类扩展的方法。具体子类为 GenericWebApplicationContext,主要是初始化属性源, // 将 ServletContext 和 ServletConfig 属性配置添加到 Environment 环境上下文中 initPropertySources(); // 校验 Environment 中那些必备的属性配置是否存在,不存在则抛异常。 getEnvironment().validateRequiredProperties(); // 创建 ApplicationEvent 事件集合 this.earlyApplicationEvents = new LinkedHashSet<>(); } }
refresh 中的 prepareRefresh 方法执行结束,主要是记录容器的启动时间、活动状态、检查必备属性是否存在。
obtainFreshBeanFactory
public abstract class AbstractApplicationContext { ... public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); ... } } ... protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 该方法也是由子类扩展,其子类有 AbstractRefreshableApplicationContext 和 GenericApplicationContext, // 该方法主要设置 BeanFactory 的 serializationId 属性值,也就是序列化id refreshBeanFactory(); // 通过 getBeanFactory 返回 BeanFactory 对象。同样也是由子类扩展,调用的是 GenericApplicationContext 类中的 getBeanFactory 方法。 // 返回的是 DefaultListableBeanFactory 。 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } ... }
obtainFreshBeanFactory 方法很简单,因为当前使用的是ClasspathXmlApplicationContext容器类,从类的继承关系可以看出执行的就是 AbstractRefreshableApplicationContext 中的 refreshBeanFactory 方法,返回的是DefaultListableBeanFactory,之后该方法还返回了 BeanFactory 对象,从这也可以看出 ApplicationContext 底层是以 BeanFactory 为基础,逐步扩展 Spring 容器功能。
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { ...... /** Bean factory for this context */ @Nullable private DefaultListableBeanFactory beanFactory; ...... @Override public final ConfigurableListableBeanFactory getBeanFactory() { synchronized (this.beanFactoryMonitor) { if (this.beanFactory == null) { throw new IllegalStateException("BeanFactory not initialized or already closed - " + "call 'refresh' before accessing beans via the ApplicationContext"); } return this.beanFactory; } } ...... }
prepareBeanFactory
prepareBeanFactory 方法主要是对 BeanFactory 做一些配置,包含各种类加载器、需要忽略的依赖以及后置处理器、解析器等
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... prepareBeanFactory(beanFactory); ... } ... } protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 设置类加载器 beanFactory.setBeanClassLoader(getClassLoader()); // 设置表达式解析器,主要用来解析 EL 表达式; Bean 初始化完成后填充属性时会用到 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 设置属性注册解析器,主要用来解析 Bean 中的各种属性类型,如 String、int 等 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // 添加一个后置处理器:ApplicationContextAwareProcessor。 // 该后置处理器用于向实现了 Aware 系列接口的 bean 设置相应属性。 // (后置处理器和 Aware 接口也是比较核心的概念,后面会有文章详细讨论) beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 以下接口,在自动注入时会被忽略,其都是 Aware 系列接口 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // 当以下特殊的 Bean 需自动注入时,指定其注入的类型 。 // 如:注入 BeanFactory 时,注入的类型对象为 ConfigurableListableBeanFactory 。 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 添加 ApplicationListenerDetector 后置处理器。 // 该后置处理器用来检测那些实现了 ApplicationListener 接口的 bean,并将其添加到应用上下文的事件广播器上。 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 判断容器中是否存在 loadTimeWeaver Bean,如果存在则上下文使用临时的 ClassLoader 进行类型匹配。 // 集成 AspectJ 时会用到 loadTimeWeaver 对象。 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 注册和环境相关的 Bean,如 environment、systemProperties、systemEnvironment 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()); } }
在 prepareBeanFactory 方法中,主要对 BeanFactory 添加了一系列属性项,如添加忽略自动注入的接口、添加 BeanPostProcessor 后置处理器、手动注册部分特殊的 Bean及环境相关的 Bean 。
postProcessBeanFactory
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... postProcessBeanFactory(beanFactory); ... } }
postProcessBeanFactory 方法是上下文准备的最后一步,spring中并没有具体去实现postProcessBeanFactory方法,是提供给想要实现BeanPostProcessor的三方框架使用的。谁要使用谁就去实现。作用是在BeanFactory准备工作完成后做一些定制化的处理,一般结合BeanPostProcessor接口的实现类一起使用,注入一些重要资源(类似Application的属性和ServletContext的属性)。最后需要设置忽略这类BeanPostProcessor子接口的自动装配。
总结
ApplicationContext 上下文准备工作基本结束,主要还是在 BeanFactory 中添加一系列后置处理器、注册特殊的 Bean 及设置忽略自动注入的接口。其中还提到了 Spring 容器的三个核心部分:Aware 系列接口、BeanPostProcessor 后置处理器、BeanDefinition ,这部分在后面的文章会逐步跟踪。
加载全部内容