refresh() 第十步:registerListeners();
我们知道,上面我们已经把事件源、多播器都注册好了,这里就是注册监听器了:
protected void registerListeners() { // 这一步和手动注册BeanDefinitionRegistryPostProcessor一样,可以自己通过set手动注册监听器 然后是最新执行的(显然此处我们无自己set) for (ApplicationListener<?> listener : getApplicationListeners()) { // 把手动注册的监听器绑定到广播器 getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! // 取到容器里面的所有的监听器的名称,绑定到广播器 后面会广播出去这些事件的 // 同时提醒大伙注意:此处并没有说到ApplicationListenerDetector这个东东,下文会分解 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... // 这一步需要注意了:如果存在早期应用事件,这里就直接发布了(同时就把earlyApplicationEvents该字段置为null) // Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
refresh() 第十一步:finishBeanFactoryInitialization(beanFactory)
这进行这一步之前,我这里截图看看,当前工厂里的Bean的的一个情况:
容器内所有的单例Bean们: 有的是提前经历过getBean()被提前实例化了,有的是直接addSingleton()方法直接添加的
容器内所有的Bean定义信息: 我们能够发现,我们自己@Bean进去的目前都仅仅存在于Bean定义信息内,还并没有真正的实例化。这就是我们这一步需要做的事~~~~
这里先建立一个快照,等执行完成这一步之后,再截图对比。
创建所有非懒加载的单例类(并invoke BeanPostProcessors)。这一步可谓和我们开发者打交道最多的,我们自定义的Bean绝大都是在这一步被初始化的,包括依赖注入等等~
因此了解这一步,能让我们更深入的了解Spring是怎么管理我们的Bean的声明周期,以及依赖关系的。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. // 初始化上下文的转换服务,ConversionService是一个类型转换接口 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)); } // Register a default embedded value resolver if no bean post-processor // (such as a PropertyPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. // 设置一个内置的值处理器(若没有的话),该处理器作用有点像一个PropertyPlaceholderConfigurer bean if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. // 注意此处已经调用了getBean方法,初始化LoadTimeWeaverAware Bean // getBean()方法的详细,下面会详细分解 // 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. // 缓存(冻结)所有的bean definition数据,不期望以后会改变 beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. // 这个就是最重要的方法:会把留下来的Bean们 不是lazy懒加载的bean都实例化掉 // bean真正实例化的时刻到了 beanFactory.preInstantiateSingletons(); } @Override public void freezeConfiguration() { this.configurationFrozen = true; this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames); }
接下来重点看看DefaultListableBeanFactory#preInstantiateSingletons
:实例化所有剩余的单例Bean
@Override public void preInstantiateSingletons() throws BeansException { // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. // 此处目的,把所有的bean定义信息名称,赋值到一个新的集合中 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { //getMergedLocalBeanDefinition:见下~ RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 不是抽象类&&是单例&&不是懒加载 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 这是Spring提供的对工程bean模式的支持:比如第三方框架的继承经常采用这种方式 // 如果是工厂Bean,那就会此工厂Bean放进去 if (isFactoryBean(beanName)) { // 拿到工厂Bean本省,注意有前缀为:FACTORY_BEAN_PREFIX Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } // true:表示渴望马上被初始化的,那就拿上执行初始化~ if (isEagerInit) { getBean(beanName); } } } else { // 这里,就是普通单例Bean正式初始化了~ 核心逻辑在方法:doGetBean // 关于doGetBean方法的详解:下面有贴出博文,专文讲解 getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... // SmartInitializingSingleton:所有非lazy单例Bean实例化完成后的回调方法 Spring4.1才提供 //SmartInitializingSingleton的afterSingletonsInstantiated方法是在所有单例bean都已经被创建后执行的 //InitializingBean#afterPropertiesSet 是在仅仅自己被创建好了执行的 // 比如EventListenerMethodProcessor它在afterSingletonsInstantiated方法里就去处理所有的Bean的方法 // 看看哪些被标注了@EventListener注解,提取处理也作为一个Listener放到容器addApplicationListener里面去 for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { // 比如:ScheduledAnnotationBeanPostProcessor CacheAspectSupport MBeanExporter等等 smartSingleton.afterSingletonsInstantiated(); } } } }
此处必须说明:此处绝大部分的单例Bean定义信息都会被实例化,但是如果是通过
FactoryBean
定义的,它是懒加载的(如果没人使用,就先不会实例化。只会到使用的时候才实例化~)。如下例子:
@Configuration public class RootConfig { @Bean public Person person() { System.out.println("this is from @Bean person"); return new Person(); } @Bean("personFactoryBean") public FactoryBean<Person> personFactoryBean() { return new FactoryBean<Person>() { @Override public Person getObject() throws Exception { System.out.println("this is from personFactoryBean"); return new Person(); } @Override public Class<?> getObjectType() { return Person.class; } }; } }
默认情况下,person()会被启动时候,实例化,但是personFactoryBean()不会。
此时通过applicationContext.getBeanDefinitionNames()能找到personFactoryBean这个Bean定义。并且通过.beanFactory.getSingletonNames()也能找到personFactoryBean这个单例Bean,所以其实此时容器内的Bean是FactoryBean而不是真正的Bean,只有在真正使用的时候,才会create一个真正的Bean出来~
比如我只需要在某个组件内注入一下:
@Autowired @Qualifier("personFactoryBean") private Person person;
这个FactoryBean#getObject就会立马执行了~
getMergedLocalBeanDefinition方法分解:
这里先解释一下getMergedLocalBeanDefinition方法的含义,因为这个方法会常常看到。
Bean定义公共的抽象类是AbstractBeanDefinition,普通的Bean在Spring加载Bean定义的时候,实例化出来的是GenericBeanDefinition,而Spring上下文包括实例化所有Bean用的AbstractBeanDefinition是RootBeanDefinition,这时候就使用getMergedLocalBeanDefinition方法做了一次转化,将非RootBeanDefinition转换为RootBeanDefinition以供后续操作。
// 该方法功能说明:在map缓存中把Bean的定义拿出来。交给getMergedLocalBeanDefinition处理。最终转换成了RootBeanDefinition类型 //在转换的过程中如果BeanDefinition的父类不为空,则把父类的属性也合并到RootBeanDefinition中, //所以getMergedLocalBeanDefinition方法的作用就是获取缓存的BeanDefinition对象并合并其父类和本身的属性 //注意如果当前BeanDefinition存在父BeanDefinition,会基于父BeanDefinition生成一个RootBeanDefinition,然后再将调用OverrideFrom子BeanDefinition的相关属性覆写进去 protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { // Quick check on the concurrent map first, with minimal locking. RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); if (mbd != null) { return mbd; } return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); } getBeanDefinition(beanName):方法如下 // 这一步说白了:就是把前面已经保存在IOC容器里的BeanDefinition定义信息 @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { BeanDefinition bd = this.beanDefinitionMap.get(beanName); if (bd == null) { if (this.logger.isTraceEnabled()) { this.logger.trace("No bean named '" + beanName + "' found in " + this); } throw new NoSuchBeanDefinitionException(beanName); } return bd; }
getBean():创建Bean的核心方法
getBean()方法为创建Bean,包括初始化剩余的单实例Bean时候的核心方法,专门写了一篇博文来介绍它,请移步此处:【小家Spring】AbstractBeanFactory#getBean()、doGetBean完成Bean的初始化、实例化,以及BeanPostProcessor后置处理器源码级详细分析
至此,finishBeanFactoryInitialization这一步完成,所有的单例Bean已经创建完成并放置容器里。
refresh() 第十二步:finishRefresh()
refresh做完之后需要做的其他事情。
protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). // 这个是Spring5.0之后才有的方法 // 表示清除一些resourceCaches,如doc说的 清楚context级别的资源缓存,比如ASM的元数据 clearResourceCaches(); // Initialize lifecycle processor for this context. // 初始化所有的LifecycleProcessor 详见下面 initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. // 上面注册好的处理器,这里就拿出来,调用它的onRefresh方法了 getLifecycleProcessor().onRefresh(); // Publish the final event. // 发布容器刷新的事件: publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. // 和MBeanServer和MBean有关的。相当于把当前容器上下文,注册到MBeanServer里面去。 // 这样子,MBeanServer持久了容器的引用,就可以拿到容器的所有内容了,也就让Spring支持到了MBean的相关功能 LiveBeansView.registerApplicationContext(this); }
initLifecycleProcessor():
在 Spring 中还提供了 Lifecycle 接口, Lifecycle 中包含start/stop方法,实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在Spring关闭的时候调用 stop方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对 MQ 进行轮询等)。而ApplicationContext的初始化最后正是保证了这一功能的实现。
当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新,而在LifecycleProcessor的使用前首先需要初始化。
// 这个初始化逻辑比较简单 protected void initLifecycleProcessor() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 如果工厂里已经存在LifecycleProcessor,那就拿出来,把值放上去this.lifecycleProcessor if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) { this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class); } // 一般情况下,都会注册上这个默认的处理器DefaultLifecycleProcessor else { DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor(); defaultProcessor.setBeanFactory(beanFactory); this.lifecycleProcessor = defaultProcessor; // 直接注册成单例Bean进去容器里 beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor); } }
初始化生命周期处理器,并设置到Spring容器中(LifecycleProcessor)
调用生命周期处理器的onRefresh方法,这个方法会找出Spring容器中实现了SmartLifecycle接口的类并进行start方法的调用
发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作
调用LiveBeansView的registerApplicationContext方法:如果设置了JMX相关的属性,则就调用该方法
发布EmbeddedServletContainerInitializedEvent事件告知对应的ApplicationListener进行响应的操作
getLifecycleProcessor().onRefresh():DefaultLifecycleProcessor讲解
备注:LifecycleProcessor作为一个Bean,它自己也实现了Lifecycle这个接口。LifecycleProcessor和DefaultLifecycleProcessor都是Spring3.0提供的,Lifecycle在Spring2.0就有了,但子接口SmartLifecycle是Spring3.0后提供的
public interface LifecycleProcessor extends Lifecycle {} public interface SmartLifecycle extends Lifecycle, Phased { // 是否伴随这容器的启动而启动 true表示容器refreshed它就会启动了 // false:必须显示的执行了它的start()才行 boolean isAutoStartup(); // 相比于Lifecycle 的stop,增加了回调函数 void stop(Runnable callback); } public interface Phased { // 权重值 int getPhase(); }
这里的处理器(只能有一个),就是我们上面注册好了的DefaultLifecycleProcessor
,我们看看它的主要方法:
- 启动和关闭调用的顺序是很重要的。如果两个对象之间存在依赖关系,依赖类要在其依赖类后启动,依赖类也要在其依赖类前停止。
// Lifecycle的方法 @Override public void start() { // 传false,表示Bean一定会启动 startBeans(false); this.running = true; } @Override public void stop() { stopBeans(); this.running = false; } @Override public boolean isRunning() { return this.running; } // LifecycleProcessor的方法 //getLifecycleProcessor().onRefresh(); 这个方法才是容器启动时候自动会调用的,其余都不是 // 显然它默认只会执行实现了SmartLifecycle接口并且isAutoStartup = true的Bean的start方法 @Override public void onRefresh() { startBeans(true); this.running = true; } // 容器关闭的时候自动会调的 @Override public void onClose() { stopBeans(); this.running = false; } // 而到底bean实现的Lifecyle的start()、stop()方法是否会调用呢? 请看下文 //======================startBeans和stopBeans LifecycleGroup#start====================== // autoStartupOnly:是否仅支持自动启动 // true:只支持伴随容器启动 (bean必须实现了`SmartLifecycle`接口且isAutoStartup为true才行) // false:表示无所谓。都会执行bean的start方法======= private void startBeans(boolean autoStartupOnly) { //拿到所有的实现了Lifecycle/SmartLifecycle的 已经在IOC容器里面的单例Bean们(备注:不包括自己this,也就是说处理器自己不包含进去) // 这里若我们自己没有定义过实现Lifecycle的Bean,这里就是空的 Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); // phases 这个Map,表示按照phase 值,吧这个Bean进行分组,最后分组执行 Map<Integer, LifecycleGroup> phases = new HashMap<>(); lifecycleBeans.forEach((beanName, bean) -> { // 若Bean实现了SmartLifecycle 接口并且标注是AutoStartup 或者 强制要求自动自行的autoStartupOnly = true if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) { int phase = getPhase(bean); LifecycleGroup group = phases.get(phase); if (group == null) { group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly); phases.put(phase, group); } // 添加到phase 值相同的组 分组嘛 group.add(beanName, bean); } }); if (!phases.isEmpty()) { List<Integer> keys = new ArrayList<>(phases.keySet()); // 此处有个根据key从小到大的排序,然后一个个的调用他们的start方法 Collections.sort(keys); for (Integer key : keys) { // 这里调用LifecycleGroup#start() 如下 phases.get(key).start(); } } } //LifecycleGroup#start() public void start() { if (this.members.isEmpty()) { return; } if (logger.isInfoEnabled()) { logger.info("Starting beans in phase " + this.phase); } // 按照权重值进行排序 若没有实现Smart接口的 权重值都为0 Collections.sort(this.members); for (LifecycleGroupMember member : this.members) { if (this.lifecycleBeans.containsKey(member.name)) { // 一次执行这些Bean的start方法(这里面逻辑就没啥好看的,只有一个考虑到getBeanFactory().dependenciesForBean控制Bean的依赖关系的) doStart(this.lifecycleBeans, member.name, this.autoStartupOnly); } } } //stopBeans原理基本同startBeans,只是顺序是倒序的,此处省略
就这样,实现了Lifecycle接口的Bean start方法什么时候调用就有门路了。
从上面的源码中,我们能够读出什么异常的地方呢?我们发现Lifecycle这个接口并不能直接使用。
因为DefaultLifecycleProcessor的onRefresh方法传值为autoStartupOnly=true:表示只有实现了SmartLifecycle的Bean才会调用start方法,因为实现了SmartLifecycle接口会有一个phase值,根据上面源码会根据此值分组执行。
autoStartupOnly=false则只要是Lifecycle 的实现既可以被调用,我们会给其默认的phase。
所以,我们要想要这个功能,请实现SmartLifecycle,而不是Lifecycle接口
结论:
- Spring的IoC容器启动过程中,默认只会执行实现了SmartLifecycle接口且isAutoStartup()=true的Bean的start()方法的。(所以你要想容器启动后就执行,请实现SmartLifecycle吧)
- AbstractApplicationContext#start() 手动调用触发。常见的一般这么做的:
context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+")); context.start();