Spring IOC ApplicationContext 源码分析

作为Spring提供的较之 BeanFactory 更为先进的IoC容器实现, ApplicationContext 除了拥有BeanFactory 支持的所有功能之外,还进一步扩展了基本容器的功能,包括 BeanFactoryPostProcessor 、 BeanPostProcessor 以及其他特殊类型bean的自动识别、容器启动后bean实例的自动初始化、国际化的信息支持、容器内事件发布等。

ApplicationContext 继承结构

image

ApplicationContext 的继承机构可以看到, ApplicationContext 继承了BeanFactory,也就是说,ApplicationContext 拥有BeanFactory的全部功能,ApplicationContext 是通过将容器的功能委派给DefaultListableBeanFactory来实现。除了继承BeanFactory,还有ResourceLoaderEnvironmentCapableApplicationEventPublisherMessageSource等接口,也就说明ApplicationContext 除了容器的功能外,还囊括了资源的处理、环境、事件发布、国际化等。

ApplicationContext 源码

创建一个常用的ApplicationContext

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");

ApplicationContext 初始化

ClassPathXmlApplicationContext的构造函数在设置完配置文件的位置后,紧接着调用refresh()方法。refresh方法是加载或刷新配置的信息,同时加载容器的单例。

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 为刷新准备这个context。
        prepareRefresh();

        // 告诉子类刷新内部bean工厂。
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 准备好bean工厂,以便在此context中使用。
        prepareBeanFactory(beanFactory);

        try {
            // 允许在context子类中对BeanFactory进行post-processing。
            postProcessBeanFactory(beanFactory);

            // 调用在context中注册为bean的工厂处理器(BeanFactoryPostProcessor)。
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册拦截bean创建的BeanProcessor。
            registerBeanPostProcessors(beanFactory);

            // 为context初始化消息源。
            initMessageSource();

            // 为context初始化事件多播。
            initApplicationEventMulticaster();

            // 初始化子类context中的其他特殊bean。
            onRefresh();

            // 检查listener类型的bean并注册它们。
            registerListeners();

            // 实例化所有剩余的(non-lazy-init)单例。
            finishBeanFactoryInitialization(beanFactory);

            // 最后一步:发布相应的事件。
            finishRefresh();
        }

        catch (BeansException ex) {
            ...
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

obtainFreshBeanFactory

obtainFreshBeanFactory()方法核心是内部调用refreshBeanFactory()方法并将容器内部的ConfigurableListableBeanFactory返回,从这也看到了ApplicationContext和BeanFactory的关系:ApplicationContext内部包含一个BeanFactory,ApplicationContext所有关于BeanFactory的功能将委派给此BeanFactory处理。

AbstractRefreshableApplicationContext#refreshBeanFactory源码:

protected final void refreshBeanFactory() throws BeansException {
   // 清理之前的BeanFactory
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      // createBeanFactory方法直接新建一个DefaultListableBeanFactory,也就是说内部使用的是DefaultListableBeanFactory实例
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      // 自定义此上下文使用的内部bean工厂
      customizeBeanFactory(beanFactory);
      // 将BeanDefinition加载到给定的bean工厂中,通常通过委托给一个或多个BeanDefinitionReader来实现
      // 子类实现的方法,此处调用的是AbstractXmlApplicationContext的方法
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException(...);
   }
}

也就是说这一步是构建ApplicationContext内部的BeanFactory,以及根据配置将BeanDefinition加载到BeanFactory中。

prepareBeanFactory

配置工厂的标准上下文特征,比如上下文的类加载器和后处理器。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // 告诉内部bean工厂使用上下文的ClassLoader等。
   beanFactory.setBeanClassLoader(getClassLoader());
   // 使用Spring的表达式模块解析和计算Spring EL表达式
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   // 属性编辑器
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // 这个在BeanFactory源码提到过的,扩展的Aware类型通过BeanPostProcessor来装配
   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);

   // 注册为可装配的依赖,而不是bean
   // MessageSource注册为bean
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // 注册early post-processor检测bean是否为applicationlistener。
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // 检测LoadTimeWeaver并为织入做准备
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // 为类型匹配设置一个临时类加载器。
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // 注册默认的环境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());
   }
}

postProcessBeanFactory

对BeanFactory预处理,ClassPathXmlApplicationContext未重写,WebXmlApplicationContext有重写,这里不展开。

invokeBeanFactoryPostProcessors

在任何应用程序bean的实例化之前,实例化并调用所有已注册的BeanFactoryPostProcessor bean,如果实现了PriorityOrdered或者Ordered接口这按顺序调用。

invokeBeanFactoryPostProcessors方法主要有两个调用:

  1. invokeBeanFactoryPostProcessors,调用BeanFactoryPostProcessors
  2. 检测LoadTimeWeaver,选择添加LoadTimeWeaverAwareProcessor,这一步在prepareBeanFactory已经做了

invokeBeanFactoryPostProcessors方法逻辑很简单

  1. 如果beanFactory是BeanDefinitionRegistry,则先处理BeanDefinitionRegistryPostProcessor
  2. 处理完ApplicationContext的BeanDefinitionRegistryPostProcessor后,实例化beanFactory的BeanDefinitionRegistryPostProcessor,按照PriorityOrdered -> Ordered -> non,顺序处理
  3. 按照BeanFactoryPostProcessor的方法,处理以上所有的,包括BeanDefinitionRegistryPostProcessor
  4. 还没完,第二步是取出beanFactory的BeanDefinitionRegistryPostProcessor,还有部分它的超类BeanFactoryPostProcessor未处理。按照2、3步处理未执行的BeanFactoryPostProcessor

registerBeanPostProcessors

在任何应用程序bean的实例化之前,按照顺序,实例化并调用所有已注册的BeanPostProcessor bean。

注册BeanPostProcessor和注册BeanFactoryPostProcessor类似,主要步骤

  1. 注册BeanPostProcessorChecker,当bean在BeanPostProcessor实例化过程中创建时,它记录一个信息消息
  2. 从beanFactory中取出按照BeanPostProcessor类型取出postProcessorNames,然后实例化,按照PriorityOrdered -> Ordered -> non的顺序依次注册到beanFactory
  3. 注册一个ApplicationListenerDetector用于检测实例化的bean是否为一个ApplicationListeners,是则注册listener

initMessageSource

MessageSource用于处理I18n,获取多语言信息。这一步,初始化MessageSource,如果在此context中没有定义任何值,则使用DelegatingMessageSource,实际是委派给父类的。

initApplicationEventMulticaster

初始化ApplicationEventMulticaster。如果上下文中没有定义,则使用SimpleApplicationEventMulticaster。

onRefresh

子类实现用于刷新context特殊的初始化工作,在实例化单例之前调用特定bean的初始化。

registerListeners

添加实现ApplicationListener接口,作为Listener的bean。不会影响其他Listener监听事件,添加是BeanName,而不是实例化后的Bean。Listener注册到ApplicationEventMulticaster。主要步骤:

  1. 注册ApplicationContext特定的Listener
  2. BeanFactory取出ApplicationListener的BeanNames,这里不初始化bean,而是注册Listener BeanName
  3. 广播earlyApplicationEvents

finishBeanFactoryInitialization

完成此上下文bean工厂的初始化,初始化所有剩余的单例bean。 与BeanFactory不同的是,ApplicationContext是eager模式,这一步主要是直接调用BeanFactory的初始化方法,完成所有non-lazy-init的bean的初始化

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // 初始化Context的类型转换服务。
   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));
   }

   // 注册一个默认的ValueResolver,主要是为了解决注解的属性值,默认用Environment的propertyResolver
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }

   // 先初始化LoadTimeWeaverAware,用于运行时织入
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);

   // Allow for caching all bean definition metadata, not expecting further changes.
   beanFactory.freezeConfiguration();

   // 实例化所有剩余的(non-lazy-init)单例。
   beanFactory.preInstantiateSingletons();
}

实例化所有的bean就是遍历所有的beanNames,然后挨个调用getBean(beanName),bean的初始化在BeanFactory 源码分析已经分析过了。这里还有一步是检测SmartInitializingSingleton

if (singletonInstance instanceof SmartInitializingSingleton) {
    final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
    smartSingleton.afterSingletonsInstantiated();
}

也就是说bean还可以实现SmartInitializingSingleton完成最后的init工作。

finishRefresh

完成此上下文的刷新,调用LifecycleProcessor的onRefresh()方法并发布ContextRefreshedEvent。

protected void finishRefresh() {
   // 清除context级资源缓存
   clearResourceCaches();

   // 为这个context初始化生命周期处理器,默认为DefaultLifecycleProcessor
   initLifecycleProcessor();

   // 刷新LifecycleProcessor,调用所有Lifecycle的start方法
   getLifecycleProcessor().onRefresh();

   // 发布事件
   publishEvent(new ContextRefreshedEvent(this));

   // 。。。好像是对JMX支持
   LiveBeansView.registerApplicationContext(this);
}

这个方法主要是对于有生命周期的bean,按照分组,调用其start方法。

ApplicationContext 使用

那么到此ApplicationContext初始化也就完成了,ApplicationContext可以作为BeanFactory、时间通知、资源管理使用

// beanFactory
UserService userService = context.getBean("userService", UserService.class);

// 事件
context.addApplicationListener(new WalkListener());
context.publishEvent(new WalkEvent(new User("Jerry")));
context.publishEvent(new WalkEvent(new User("Peter")));

// locale
context.getMessage("menu.edit", null, "Edit", Locale.US);
// ...

ApplicationContext的使用部分只需要调用内部的相应的组件即可。

总结

ApplicationContext 是Spring 的完整上下文,通过将各个功能模块委派给各个组件,完成了一个完成的环境,在ApplicationContext的构造函数中,完成各个组件的初始化,以备后期使用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容