前面的文章中已经讲了如何通过Intellij搭建Spring Framework 5 的源码开发环境,下面我们来通过结合源码来解决实际问题,知道问题背后的本质。
搭建测试工程
我们通过在spring framework源码上添加一个gradle的module模块,来实现自己的一些测试功能验证,本文中的案例使用的是DEMO_01的package,截图如下:
所有代码如下
package com.jz.learning.demo.DEMO_01;
import com.jz.learning.demo.DEMO_01.config.AppConfig;
import com.jz.learning.demo.DEMO_01.pojo.Dog;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
Dog dog = applicationContext.getBean(Dog.class);
}
}
package com.jz.learning.demo.DEMO_01.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.jz.learning.demo.DEMO_01.pojo",
"com.jz.learning.demo.DEMO_01.custom_smartInitialization",
"com.jz.learning.demo.DEMO_01.custom_applicationEvent"})
public class AppConfig {
}
package com.jz.learning.demo.DEMO_01.custom_applicationEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyApplicationEventListener {
Log log = LogFactory.getLog(MyApplicationEventListener.class.getName());
@EventListener(classes = ApplicationEvent.class)
public void listenAfterAllBeanCreated(ApplicationEvent event){
log.info("ApplicationEvent Listener execute!");
}
}
package com.jz.learning.demo.DEMO_01.custom_smartInitialization;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.stereotype.Component;
@Component
public class MySmartInitialization implements SmartInitializingSingleton {
static Log log = LogFactory.getLog(MySmartInitialization.class.getName());
@Override
public void afterSingletonsInstantiated() {
log.info("All Bean Instantiated!");
}
}
package com.jz.learning.demo.DEMO_01.custom_smartInitialization;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.stereotype.Component;
@Component
public class MySmartInitialization_02 implements SmartInitializingSingleton {
static Log log = LogFactory.getLog(MySmartInitialization_02.class.getName());
@Override
public void afterSingletonsInstantiated() {
log.info("All Bean Instantiated!");
}
}
运行结果
红色框出来的是log日志的输出,可以看到,Cat和Dog两个Bean先创建,然后调用了2个自定义的MySmartInitialization的afterSingletonsInstantiatied() 方法,和一个自定义的MyApplicationEventListener事件的监听方法listenAfterAllBeanCreated()
源码分析
进入AnnotationConfigApplicationContext类
找到大名鼎鼎的refresh()方法
重点关注两个方法
finishBeanFactoryInitialization
所有的秘密都藏在源码的这两个方法背后,首先看第一个方法 finishBeanFactoryInitialization
进入后继续跟进beanFactory.preInstantiateSingletions() 方法,并找到对应实现类DefaultListableBeanFactory里的preInstantiateSingletons() 方法
在方法的结尾发现有如下一段代码
可以发现,spring源码在创建所有bean结束后的finishBeanFactoryInitialization() 方法中调用了DefaultListableBeanFactory的preInstantiateSingletons()方法的结尾处,对所有的bean进行遍历,如果该类实现了SmartInitializingSingleton接口,则调用该接口里的afterSingletonsInstantiated()方法。
finishRefresh
接着来看另外一种实现方式,通过监听ApplicationEvent时间来实现,答案就在finishRefresh()方法里
继续跟进代码
知道一个方法叫publishEvent() ,如上截图所示,然后继续跟进
最后会调用到 multicastEvent方法,并且遍历执行所有的Listener
总结
本文在源码中搭建了一个项目工程,实现了在所有bean创建完后触发事件,有两种方法可以实现:1)通过继承SmartInitializingSingleton接口,2)通过添加ApplicationEvent的EventListener。
最后通过源码分析,阐述了两种方法实现的本质原理。