摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。

在 Spring 中还提供了 Lifecycle 接口, Lifecycle 中包含start/stop方法,实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在Spring关闭的时候调用 stop方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对 MQ 进行轮询等)。而ApplicationContext的初始化最后正是保证了这一功能的实现。

  1. /**
  2. * Finish the refresh of this context, invoking the LifecycleProcessor's
  3. * onRefresh() method and publishing the
  4. * {@link org.springframework.context.event.ContextRefreshedEvent}.
  5. */
  6. protected void finishRefresh() {
  7. // Clear context-level resource caches (such as ASM metadata from scanning).
  8. clearResourceCaches();
  9.  
  10. // Initialize lifecycle processor for this context.
  11. initLifecycleProcessor();
  12.  
  13. // Propagate refresh to lifecycle processor first.
  14. getLifecycleProcessor().onRefresh();
  15.  
  16. // Publish the final event.
  17. publishEvent(new ContextRefreshedEvent(this));
  18.  
  19. // Participate in LiveBeansView MBean, if active.
  20. LiveBeansView.registerApplicationContext(this);
  21. }

一、initLifecycleProcessor

当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新,而在LifecycleProcessor的使用前首先需要初始化。

  1. /**
  2. * Initialize the LifecycleProcessor.
  3. * Uses DefaultLifecycleProcessor if none defined in the context.
  4. * @see org.springframework.context.support.DefaultLifecycleProcessor
  5. */
  6. protected void initLifecycleProcessor() {
  7. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  8. if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
  9. this.lifecycleProcessor =
  10. beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
  11. if (logger.isTraceEnabled()) {
  12. logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
  13. }
  14. }
  15. else {
  16. DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
  17. defaultProcessor.setBeanFactory(beanFactory);
  18. this.lifecycleProcessor = defaultProcessor;
  19. beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
  20. if (logger.isTraceEnabled()) {
  21. logger.trace("Unable to locate LifecycleProcessor with name '" +
  22. LIFECYCLE_PROCESSOR_BEAN_NAME +
  23. "': using default [" + this.lifecycleProcessor + "]");
  24. }
  25. }
  26. }

二、onRefresh

启动所有实现了Lifecycle接口的bean。

  1. @Override
  2. public void onRefresh() {
  3. startBeans(true);
  4. this.running = true;
  5. }
  6.  
  7. // Internal helpers
  8.  
  9. private void startBeans(boolean autoStartupOnly) {
  10. Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
  11. Map<Integer, LifecycleGroup> phases = new HashMap<>();
  12. lifecycleBeans.forEach((beanName, bean) -> {
  13. if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
  14. int phase = getPhase(bean);
  15. LifecycleGroup group = phases.get(phase);
  16. if (group == null) {
  17. group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
  18. phases.put(phase, group);
  19. }
  20. group.add(beanName, bean);
  21. }
  22. });
  23. if (!phases.isEmpty()) {
  24. List<Integer> keys = new ArrayList<>(phases.keySet());
  25. Collections.sort(keys);
  26. for (Integer key : keys) {
  27. phases.get(key).start();
  28. }
  29. }
  30. }

三、publishEvent

当完成ApplicationContext初始化的时候,要通过Spring中的事件发布机制来发出ContextRefreshedEvent事件,以保证对应的监听器可以做进一步的逻辑处理。

  1. /**
  2. * Publish the given event to all listeners.
  3. * <p>Note: Listeners get initialized after the MessageSource, to be able
  4. * to access it within listener implementations. Thus, MessageSource
  5. * implementations cannot publish events.
  6. * @param event the event to publish (may be an {@link ApplicationEvent}
  7. * or a payload object to be turned into a {@link PayloadApplicationEvent})
  8. */
  9. @Override
  10. public void publishEvent(Object event) {
  11. publishEvent(event, null);
  12. }
  13.  
  14. /**
  15. * Publish the given event to all listeners.
  16. * @param event the event to publish (may be an {@link ApplicationEvent}
  17. * or a payload object to be turned into a {@link PayloadApplicationEvent})
  18. * @param eventType the resolved event type, if known
  19. * @since 4.2
  20. */
  21. protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
  22. Assert.notNull(event, "Event must not be null");
  23.  
  24. // Decorate event as an ApplicationEvent if necessary
  25. ApplicationEvent applicationEvent;
  26. if (event instanceof ApplicationEvent) {
  27. applicationEvent = (ApplicationEvent) event;
  28. }
  29. else {
  30. applicationEvent = new PayloadApplicationEvent<>(this, event);
  31. if (eventType == null) {
  32. eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
  33. }
  34. }
  35.  
  36. // Multicast right now if possible - or lazily once the multicaster is initialized
  37. if (this.earlyApplicationEvents != null) {
  38. this.earlyApplicationEvents.add(applicationEvent);
  39. }
  40. else {
  41. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
  42. }
  43.  
  44. // Publish event via parent context as well...
  45. if (this.parent != null) {
  46. if (this.parent instanceof AbstractApplicationContext) {
  47. ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
  48. }
  49. else {
  50. this.parent.publishEvent(event);
  51. }
  52. }
  53. }

Spring源码分析(二十五)finishRefresh的更多相关文章

  1. Spring源码分析(十五)获取单例

    本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 之前我们讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例be ...

  2. ABP源码分析二十五:EventBus

    IEventData/EventData: 封装了EventData信息,触发event的源对象和时间 IEventBus/EventBus: 定义和实现了了一系列注册,注销和触发事件处理函数的方法. ...

  3. Vue.js 源码分析(二十五) 高级应用 插槽 详解

    我们定义一个组件的时候,可以在组件的某个节点内预留一个位置,当父组件调用该组件的时候可以指定该位置具体的内容,这就是插槽的用法,子组件模板可以通过slot标签(插槽)规定对应的内容放置在哪里,比如: ...

  4. Spring源码分析(十八)创建bean

    本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.创建bean的实例 1. autowireConstructor 2 ...

  5. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  6. spark 源码分析之十五 -- Spark内存管理剖析

    本篇文章主要剖析Spark的内存管理体系. 在上篇文章 spark 源码分析之十四 -- broadcast 是如何实现的?中对存储相关的内容没有做过多的剖析,下面计划先剖析Spark的内存机制,进而 ...

  7. Spring源码分析(十二)FactoryBean的使用

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 一般情况下,Spring通过反射机制利用bean的class属性指定实现 ...

  8. Spring源码分析(十九)容器的功能扩展概览

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过前面几章的分析,相信大家已经对 Spring 中的容器功能有了简单 ...

  9. Spring源码分析(十六)准备创建bean

    本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多Spring ...

  10. Android源码分析(十五)----GPS冷启动实现原理分析

    一:原理分析 主要sendExtraCommand方法中传递两个参数, 根据如下源码可以知道第一个参数传递delete_aiding_data,第二个参数传递null即可. @Override pub ...

随机推荐

  1. PHP中常用的魔术方法

    我们在PHP中经常用到魔术方法,像构造方法,析构方法等等魔术变量,下面总结一下一些常用的魔术变量: __construct(),__destruct(),__clone(),__autoload(), ...

  2. CSS属性之attr()

    attr()准确的说,不应该是一个属性,而是一个CSS的函数,我们先看看MDN上的介绍吧: Summary The attr() CSS function is used to retrieve th ...

  3. C# 2个List<T>比较内部项是否相等(全部相等则相等,反之不相等)

    static void Main(string[] args) { List<string> a = new List<string>() { "a", & ...

  4. opencv3.2.0形态学滤波之开运算、闭运算

    /* 一.开运算: (1)开运算,其实就是先腐蚀后膨胀的过程. (2)数学表达式:dst = open(src,element) = dilate(erode(src,element)) (3)作用: ...

  5. 管理DnS服务器知识点

    DNS服务器是计算机域名系统 (Domain Name System 或Domain Name Service) 的缩写,它是由域名解析器和域名服务器组成的.域名服务器是指保存有该网络中所有主机的域名 ...

  6. Ubuntu添加源列表

    1.首先备份源列表:sudo cp /etc/apt/sources.list /etc/apt/sources.list_backup 2.清空原来的/etc/apt/sources.list,添加 ...

  7. linux ubuntu 本地镜像 软件源 制作方法

    1.配置当前软件源,镜像非常大,所以首先要配置一下载速度快的软件源http://fffo.blog.163.com/blog/static/2119130682014322104136601/2.安装 ...

  8. MySQL案例09:Last_IO_Error: Got fatal error 1236 from master when reading data from binary log

    刚处理完“挖矿”事件,在做最后一个MySQL NBU备份的时候,发现从库有问题,好奇的是怎么主从状态异常没有告警呢?先不管这么多了,处理了这个问题再完善告警内容. 一.错误信息 从库show slav ...

  9. mysql-5.7 持久化统计信息详解

    一.持久化统计信息的意义: 统计信息用于指导mysql生成执行计划,执行计划的准确与否直接影响到SQL的执行效率:如果mysql一重启 之前的统计信息就没有了,那么当SQL语句来临时,那么mysql就 ...

  10. 导出AD用户所属组,查询AD用户(aduser)

    $ous="admin","bladmin","af","dd"for($i=0;$i -lt 2;$i++) { $o ...