Spring_13_Spring的单实例Bean创建后发布相应的事件

Spring_13_IOC容器的刷新过程_10

在上一篇文章中,我们花费了大量的篇幅来讲解IOC中最最重要的一步,这篇文章我们来讲解IOC中的最后一步:发布相应的事件。

如果我们分析完毕之后发现篇幅较少,那么我们把Spring中的循环依赖加进去,因为在上一篇文章中我们在创建单实例Bean的时候,被创建的只是一个简单的Bean而已,我们来将它补充进去,既然要讲,就要讲细,将全。

我们先来看最后的第12大步骤

由于第十二步里面的方法体不算太多,我们直接贴在下面:

protected void finishRefresh() {
  // Clear context-level resource caches (such as ASM metadata from scanning).
  // 清理上下文级别的资源缓存
  clearResourceCaches();

  // 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.
  if (!NativeDetector.inNativeImage()) {
    LiveBeansView.registerApplicationContext(this);
  }
}

总体看是有五个步骤,我们挨个来说:

步骤一:清理上下文级别的缓存

在当前默认的资源加载器对象中,调用资源缓存的清理方法(其实就是Map中的clear方法),清理我们本次IOC刷新过程中的缓存资源,但是此时我们可以看见这个缓存中现在是没有任何资源被缓存进来的。

步骤二:初始化生命周期处理器

拿到当前上下文中的Bean工厂,判断当前的Bean工厂中是否有beanName为lifecycleProcessor的Bean对象。

补充:这个判断方法我们在之前已经分析过,现在我们将代码贴在下面大家看一下就能知道整个的判断过程,如果还是不知道,那么可以合理利用Ctrl+F在我们过往的文章中搜一下。

@Override
public boolean containsLocalBean(String name) {
  String beanName = transformedBeanName(name);
  return ((containsSingleton(beanName) || containsBeanDefinition(beanName)) &&
          (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName)));
}

当然此时我们的Bean工厂中是不存在这个对象的,如果存在该对象的话,那么我们就拿到这个对象,将它的引用赋值给AbstractApplicationContext中的属性,保存起来。

如果不存在的话,那么创建一个默认的生命周期处理器DefaultLifecycleProcessor,该对象用来在此上下文中管理 bean 的生命周期。

创建完毕之后还是将该引用赋值到当前上下文对象中,并且将该对象直接添加到Bean工厂中的一级缓存中。

步骤三:将刷新传播到生命周期处理器

调用我们刚刚创建好的生命周期处理器对象的OnRefresh方法,在这个方法中我们看见里面又调用了startBeans(true);方法,传递了一个true进去,在往下分析之前,我们先来看一下当前默认生命周期处理器它的继承关系,帮助我们更好的向下进行。

现在我们知道我们的默认生命周期处理器中的哪几个方法是实现了哪几个接口。

接下来我们回过头在往下看这个startBeans(boolean autoStartupOnly)方法,一进入这个方法,就从Bean工厂中获取所有生命周期的Bean,返回来的是一个Map,key为bean的名字,Value为Lifecycle接口。

我们简单来看一下是怎么从Bean工厂中拿到这些特定的Bean的,先把代码贴在下面,之后我们简单讲解一下即可。

/**
	 * Retrieve all applicable Lifecycle beans: all singletons that have already been created,
	 * as well as all SmartLifecycle beans (even if they are marked as lazy-init).
	 * @return the Map of applicable beans, with bean names as keys and bean instances as values
	 */
protected Map<String, Lifecycle> getLifecycleBeans() {
  ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  Map<String, Lifecycle> beans = new LinkedHashMap<>();
  String[] beanNames = beanFactory.getBeanNamesForType(Lifecycle.class, false, false);
  for (String beanName : beanNames) {
    String beanNameToRegister = BeanFactoryUtils.transformedBeanName(beanName);
    boolean isFactoryBean = beanFactory.isFactoryBean(beanNameToRegister);
    String beanNameToCheck = (isFactoryBean ? BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
    if ((beanFactory.containsSingleton(beanNameToRegister) &&
         (!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory))) ||
        matchesBeanType(SmartLifecycle.class, beanNameToCheck, beanFactory)) {
      Object bean = beanFactory.getBean(beanNameToCheck);
      if (bean != this && bean instanceof Lifecycle) {
        beans.put(beanNameToRegister, (Lifecycle) bean);
      }
    }
  }
  return beans;
}

我们又看见了熟悉的getBeanNamesForType这个方法,拿着这个Lifecycle.class去进行匹配,之后遍历拿回来的所有的beanName,判断这Bean是不是工厂Bean,如果是工厂Bean,那么拿到这个工厂Bean为我们创建完的Bean(工厂Bean通过工厂的getObject()方法给我们创建出来),如果不是工厂Bean,那就还是正常的getBean()流程,接下来有一个判断,我们来看一下:

if ((beanFactory.containsSingleton(beanNameToRegister) &&
					(!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory))) ||
					matchesBeanType(SmartLifecycle.class, beanNameToCheck, beanFactory))

我们先把它拆开:

(beanFactory.containsSingleton(beanNameToRegister) &&
					(!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory)))
matchesBeanType(SmartLifecycle.class, beanNameToCheck, beanFactory)

这两个条件是或的关系。

我们再来拆第一个条件的判断:

beanFactory.containsSingleton(beanNameToRegister)
(!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory))

这两个条件是与的关系。

首先我们的Bean工厂中必须是存在着当前的Bean的,之后:是否是工厂Bean、这个Bean是不是Lifecycle这个接口类型的,这两个条件有一个为true即可。

上面分析的这是我们的第二个与的关系,两个都返回true之后在看当前的Bean是不是SmartLifecycle这个类型的。

上面的条件判断完成之后,符合的话就将我们的beanName和我们当前的Bean实例放在这个Map中进行返回。

现在我们已经拿到了所有的当前Bean是Lifecycle这个接口的Bean,接下来对这个Map进行遍历,在遍历的里面我们看见了我们传递的参数autoStartupOnly它起的作用,首先我们知道传递进来的是true,并且我们看这个参数的名字,都说Spring里面的参数和方法甚至是类都是见名知意的,但是此时我们并没有理解这个参数到底是要干什么,并且在这里进行取了反,看到这儿的时候,大家不要慌,继续向下看后面的判断逻辑:

(bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())

当前的bean必须是SmartLifecycle这个类型的,并且如果实现了这个接口,那么实现了isAutoStartup这个方法的同时,返回值必须给我们返回来true才可以在继续向方法的下一步进行执行。
现在大家在来看这个的判断就知道,这个参数:autoStartupOnly具体的作用了,要求我们必须是自动启动的。

再接下来就是层层的封装,把我们在上一步返回来的Map全都封装进LifecycleGroup中,封装进去的时候,又拿到Phased这个接口中的唯一的一个方法给我们返回来的一个阶段标志,不进行设置的话,默认返回0,又传递了一个每个关闭阶段的超时时间和标志这必须是自动启动的标志。将它放进集合之后,又把我们当前遍历出来的每一个Bean包装成LifecycleGroupMember放在了LifecycleGroup维护的members属性中,判断是否是SmartLifecycle这个类型的,如果是的话,那么SmartLifecycle这个类型的数量就加1。

最后开始调用start方法,判断这个members属性集合不为null,然后进行排序,挨个执行每一个Bean的start方法。

执行之前,还会判断当前的Bean不为null并且当前的Bean不是默认生命周期处理器这个Bean,看看有没有依赖的Bean,如果有,那么拿到依赖的Bean,重新进入方法。

判断当前Bean是否在运行中,不在运行中才可以调用start方法,判断是不是自动启动、是不是SmartLifecycle类型的Bean、是自动启动的。

以上的判断都校验正确后,才会真正的调用我们的自己实现了SmartLifecycle这个接口,并且重写start这个方法里面的方法体内容。

说了这么多,实现了SmartLifecycle这个接口,实现了这么多的方法,能用来干什么呢?

实现了这个接口后,Spring会保证容器在启动后调用start方法开始生命周期,并且在Spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,比如MQ进行轮询等。

步骤四:发布最终的事件

将容器刷新事件由多播器进行派发(SimpleApplicationEventMulticaster对象),并且在multicastEvent多播事件这个方法中拿到容器中所有负责监听ApplicationEvent这个事件的事件监听器(当前我们自己实在的只有一个),我们当前的容器刷新事件是属于ApplicationEvent这个事件,大家看一下ApplicationEvent这个抽象类当前在Spring中有多少实现即可,其中test包可以忽略。

步骤五:与Bean试图相关

略过,没什么用。

自此我们整个IOC容器的XML配置文件方式的简单Bean的全部刷新流程到此结束,下面我们来一点一点的继续补充IOC中的一些细节。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值