原理解析
SpringBoot的启动过程
阶段一:SpringApplication 构造
- 记录 BeanDefinition 源
- 推断应用类型
- 记录 ApplicationContext 初始化器
- 记录监听器
- 推断主启动类
阶段二:执行 run 方法
-
得到 SpringApplicationRunListeners,名字取得不好,实际是事件发布器
- 发布 application starting 事件1
-
封装启动 args
-
准备 Environment 添加命令行参数(*)
(准备环境变量,和配置变量)
-
ConfigurationPropertySources 处理(*)
(添加一个处理参数格式的处理器)
- 发布 application environment 已准备事件2
-
通过 EnvironmentPostProcessorApplicationListener 进行 env 后处理(*)
- application.properties,由 StandardConfigDataLocationResolver 解析
- spring.application.json
-
绑定 配置文件中的spring.main 到 SpringApplication 对象(*)
-
打印 banner(*)
-
创建容器
-
准备容器
- 发布 application context 已初始化事件3
-
加载 bean 定义
(有xml配置文件,包扫描,配置类3种方式加载bean定义)
- 发布 application prepared 事件4
-
refresh 容器
(这一步就对应这spring调用bean后处理工厂和bean后处理器的方法)
- 发布 application started 事件5
-
执行 runner
-
发布 application ready 事件6
-
这其中有异常,发布 application failed 事件7
-
带 * 的有独立的示例
演示 - 启动过程
com.itheima.a39.A39_1 对应 SpringApplication 构造
com.itheima.a39.A39_2 对应第1步,并演示 7 个事件
com.itheima.a39.A39_3 对应第2、8到12步
org.springframework.boot.Step3
org.springframework.boot.Step4
org.springframework.boot.Step5
org.springframework.boot.Step6
org.springframework.boot.Step7
收获💡
-
SpringApplication 构造方法中所做的操作
- 可以有多种源用来加载 bean 定义
- 应用类型推断
- 添加容器初始化器
- 添加监听器
- 演示主类推断
-
如何读取 spring.factories 中的配置
-
从配置中获取重要的事件发布器:SpringApplicationRunListeners
-
容器的创建、初始化器增强、加载 bean 定义等
-
CommandLineRunner、ApplicationRunner 的作用
(CommandLineRunner执行的是原始的参数,ApplicationRunner执行的是经过处理的参数)
-
环境对象
- 命令行 PropertySource
- ConfigurationPropertySources 规范环境键名称
- EnvironmentPostProcessor 后处理增强
- 由 EventPublishingRunListener 通过监听事件2️⃣来调用
- 绑定 spring.main 前缀的 key value 至 SpringApplication
-
Banner
内嵌容器
springboot为我们集成了tomcat服务器,下图是一个运行在tomcat上jar包的文件结构
Server
└───Service
├───Connector (协议, 端口)
└───Engine
└───Host(虚拟主机 localhost)
├───Context1 (应用1, 可以设置虚拟路径, / 即 url 起始路径; 项目磁盘路径, 即 docBase )
│ │ index.html
│ └───WEB-INF
│ │ web.xml (servlet, filter, listener) 3.0
│ ├───classes (servlet, controller, service ...)
│ ├───jsp
│ └───lib (第三方 jar 包)
└───Context2 (应用2)
│ index.html
└───WEB-INF
web.xml
SpringBoot内嵌tomcat关键代码演示
public static void main(String[] args) throws LifecycleException, IOException {
// 1.创建 Tomcat 对象
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("tomcat");
// 2.创建项目文件夹, 即 docBase 文件夹
File docBase = Files.createTempDirectory("boot.").toFile();
docBase.deleteOnExit();
// 3.创建 Tomcat 项目, 在 Tomcat 中称为 Context
Context context = tomcat.addContext("", docBase.getAbsolutePath());
WebApplicationContext springContext = getApplicationContext();
// 4.编程添加 Servlet
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
HelloServlet helloServlet = new HelloServlet();
servletContext.addServlet("aaa", helloServlet).addMapping("/hello");
DispatcherServlet dispatcherServlet = springContext.getBean(DispatcherServlet.class);
servletContext.addServlet("dispatcherServlet", dispatcherServlet).addMapping("/");
}
}, Collections.emptySet());
// 5.启动 Tomcat
tomcat.start();
// 6.创建连接器, 设置监听端口
Connector connector = new Connector(new Http11Nio2Protocol());
connector.setPort(8080);
tomcat.setConnector(connector);
}
这个是基于javaEE的servlet
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print("""
<h3>hello</h3>
""");
}
}
那么我们需要在编程添加 Servlet这一步添加基于MVC的Controller
关键代码
WebApplicationContext springContext = getApplicationContext();
// 4.编程添加 Servlet
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
// ⬇️通过 ServletRegistrationBean 添加 DispatcherServlet 等
for (ServletRegistrationBean registrationBean :
springContext.getBeansOfType(ServletRegistrationBean.class).values()) {
registrationBean.onStartup(ctx);
}
}
}, Collections.emptySet());
除此之外SpringBoot还内嵌了数据库,和内嵌缓存数据库
自动配置
SpringBoot还有一个重要的特性就是帮助我们自动配置了很多经常用到的库。
如何实现的,这是还原了部分源代码
@Configuration // 本项目的配置类
@Import(MyImportSelector.class)
static class Config {
//自己定义和第三方定义,自己定义的后加载,后加载的会覆盖先加载的
@Bean
public Bean1 bean1() {
return new Bean1("本项目");
}
}
static class MyImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> names = SpringFactoriesLoader.loadFactoryNames(MyImportSelector.class, null);
return names.toArray(new String[0]);
}
}
@Configuration // 第三方的配置类
static class AutoConfiguration1 {
@Bean
@ConditionalOnMissingBean
public Bean1 bean1() {
return new Bean1("第三方");
}
}
这里有一个非常重要的方法SpringFactoriesLoader.loadFactoryNames我们尝试打印一下他的返回值names
for (String name : names) {
System.out.println("names返回值" + name);
}
names返回值com.example.a35.A41_1.AutoConfiguration1
names返回值com.example.a35.A41_1.AutoConfiguration2
他的结果是这个,这是因为
在META-INF中有一个spring.factories的文件,他里面定义了需要加载的配置类而SpringFactoriesLoader.loadFactoryNames就是获取所有配置类并且进行自动配置.
我们可以发现SpringBoot的starter包里面会有spring.factories自动配置的文件
下面我们来介绍几种常用的库的自动配置
AopAutoConfiguration
Spring Boot 是利用了自动配置类来简化了 aop 相关配置
- AOP 自动配置类为
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
- 可以通过
spring.aop.auto=false
禁用 aop 自动配置 - AOP 自动配置的本质是通过
@EnableAspectJAutoProxy
来开启了自动代理,如果在引导类上自己添加了@EnableAspectJAutoProxy
那么以自己添加的为准 @EnableAspectJAutoProxy
的本质是向容器中添加了AnnotationAwareAspectJAutoProxyCreator
这个 bean 后处理器,它能够找到容器中所有切面,并为匹配切点的目标类创建代理,创建代理的工作一般是在 bean 的初始化阶段完成的
DataSourceAutoConfiguration
Spring Boot 管理关系型数据库的自动配置类
- 对应的自动配置类为:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- @EnableConfigurationProperties({DataSourceProperties.class}) ,通过这个来配置添加配置参数如url,username,password
简单说明一下,Spring Boot 支持两大类数据源:
- EmbeddedDatabase - 内嵌数据库连接池(测试或者是小项目使用)
- PooledDataSource - 非内嵌数据库连接池
PooledDataSource 又支持如下数据源
- hikari 提供的 HikariDataSource
- tomcat-jdbc 提供的 DataSource
- dbcp2 提供的 BasicDataSource
- oracle 提供的 PoolDataSourceImpl
MybatisAutoConfiguration
- MyBatis 自动配置类为
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
- 它主要配置了两个 bean
- SqlSessionFactory - MyBatis 核心对象,用来创建 SqlSession
- SqlSessionTemplate - SqlSession 的实现,此实现会与当前线程绑定
- 用 ImportBeanDefinitionRegistrar 的方式扫描所有标注了 @Mapper 注解的接口
- 用 AutoConfigurationPackages 来确定扫描的包
- 还有一个相关的 bean:MybatisProperties,它会读取配置文件中带
mybatis.
前缀的配置项进行定制配置
@MapperScan 注解的作用与 MybatisAutoConfiguration 类似,会注册 MapperScannerConfigurer 有如下区别
- @MapperScan 扫描具体包(当然也可以配置关注哪个注解)
- @MapperScan 如果不指定扫描具体包,则会把引导类范围内,所有接口当做 Mapper 接口
- MybatisAutoConfiguration 关注的是所有标注 @Mapper 注解的接口,会忽略掉非 @Mapper 标注的接口
这里有同学有疑问,之前介绍的都是将具体类交给 Spring 管理,怎么到了 MyBatis 这儿,接口就可以被管理呢?
- 其实并非将接口交给 Spring 管理,而是每个接口会对应一个 MapperFactoryBean,是后者被 Spring 所管理,接口只是作为 MapperFactoryBean 的一个属性来配置
TransactionAutoConfiguration
-
事务自动配置类有两个:
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
-
前者配置了 DataSourceTransactionManager 用来执行事务的提交、回滚操作
-
后者功能上对标 @EnableTransactionManagement,包含以下三个 bean
- BeanFactoryTransactionAttributeSourceAdvisor 事务切面类,包含通知和切点
- TransactionInterceptor 事务通知类,由它在目标方法调用前后加入事务操作
- AnnotationTransactionAttributeSource 会解析 @Transactional 及事务属性,也包含了切点功能
-
如果自己配置了 DataSourceTransactionManager 或是在引导类加了 @EnableTransactionManagement,则以自己配置的为准
自动装配
前面我们介绍了很多其他第三方的自动装配的原理,如果我们写的库需要自动装配需要怎么做
在SpringBoot中,需要在META-INF的spring.factories中添加
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.a35.A41_2.AutoConfiguration1,\
com.example.a35.A41_2.AutoConfiguration2
他起到的作用和上面MyImportSelector一样,不过SpringBoot会自动import
EnableAutoConfiguration
public class A41_2 {
public static void main(String[] args) throws IOException {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
StandardEnvironment env = new StandardEnvironment();
env.getPropertySources().addLast(new SimpleCommandLinePropertySource(
"--spring.datasource.url=jdbc:mysql://localhost:3306/eesy",
"--spring.datasource.username=root",
"--spring.datasource.password=123456"
));
context.setEnvironment(env);
context.registerBean("config", Config.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
String resourceDescription = context.getBeanDefinition(name).getResourceDescription();
if (resourceDescription != null)
System.out.println(name + " 来源:" + resourceDescription);
}
context.close();
}
@Configuration // 本项目的配置类
@EnableAutoConfiguration
static class Config {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
@Configuration // 第三方的配置类
static class AutoConfiguration1 {
@Bean
public Bean1 bean1() {
return new Bean1();
}
}
@Configuration // 第三方的配置类
static class AutoConfiguration2 {
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
static class Bean1 {
}
static class Bean2 {
}
}
条件装配
在应用的过程中我们往往需要进行条件装配,比如在web场景下如果导入的是tomcat依赖我们就不需要Jetty和Undertow,下面代码复刻了功能
static class MyCondition implements Condition { // 存在 Druid 依赖
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnClass.class.getName());
String className = attributes.get("className").toString();
boolean exists = (boolean) attributes.get("exists");
boolean present = ClassUtils.isPresent(className, null);
return exists ? present : !present;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Conditional(MyCondition.class)
@interface ConditionalOnClass {
boolean exists(); // true 判断存在 false 判断不存在
String className(); // 要判断的类名
}
@Configuration // 第三方的配置类
@ConditionalOnClass(className = "com.alibaba.druid.pool.DruidDataSource", exists = false)
static class AutoConfiguration1 {
@Bean
public Bean1 bean1() {
return new Bean1();
}
}
@Value注入底层
概况:Spring中Environment中存放可能用到的参数context会对他进行解析比如解析 ${}
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A39.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
test1(context, resolver, Bean1.class.getDeclaredField("home"));
test2(context, resolver, Bean1.class.getDeclaredField("age"));
}
private static void test2(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
// 获取 @Value 的内容
String value = resolver.getSuggestedValue(dd1).toString();
System.out.println(value);
// 解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
System.out.println(value.getClass());
Object age = context.getBeanFactory().getTypeConverter().convertIfNecessary(value, dd1.getDependencyType());
System.out.println(age.getClass());
}
private static void test1(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
// 获取 @Value 的内容
String value = resolver.getSuggestedValue(dd1).toString();
System.out.println(value);
// 解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
}
public class Bean1 {
@Value("${JAVA_HOME}")
private String home;
@Value("18")
private int age;
}
同时@Value还可以导入Bean
private static void test3(AnnotationConfigApplicationContext context, ContextAnnotationAutowireCandidateResolver resolver, Field field) {
DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
// 获取 @Value 的内容
String value = resolver.getSuggestedValue(dd1).toString();
System.out.println(value);
// 解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
System.out.println(value.getClass());
// 解析 #{} @bean3
Object bean3 = context.getBeanFactory().getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));
// 类型转换
Object result = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3, dd1.getDependencyType());
System.out.println(result);
}
public class Bean2 {
@Value("#{@bean3}") // SpringEL #{SpEL}
private Bean3 bean3;
}
@Autowired导入底层
DependencyDescriptor在@Autowired中这个类比较关键,他负责描述了,注入bean的依赖
成员变量注入
DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
Object bean1 = beanFactory.doResolveDependency(dd1, "bean1", null, null);
@Autowired
private Bean2 bean2;
根据参数类型注入
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), false);
Object bean2 = beanFactory.doResolveDependency(dd2, "bean2", null, null);
@Autowired
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
包装为 Optional
DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
dd3.increaseNestingLevel();
Object bean3 = beanFactory.doResolveDependency(dd3, "bean3", null, null);
increaseNestingLevel只有我们调用了这个方法之后会获取到Bean2
@Autowired
private Optional<Bean2> bean3;
包装为 ObjectProvider,ObjectFactory
DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean4"), false);
if (dd4.getDependencyType() == ObjectFactory.class) {
dd4.increaseNestingLevel();
Object bean4 = beanFactory.doResolveDependency(dd4, "bean1", null, null);
System.out.println(bean4);
}
@Autowired
private ObjectFactory<Bean2> bean4;
数组类型
private static void testArray(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd1 = new DependencyDescriptor(Target.class.getDeclaredField("serviceArray"), true);
if (dd1.getDependencyType().isArray()) {
Class<?> componentType = dd1.getDependencyType().getComponentType();
System.out.println(componentType);
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, componentType);
List<Object> beans = new ArrayList<>();
for (String name : names) {
System.out.println(name);
Object bean = dd1.resolveCandidate(name, componentType, beanFactory);
beans.add(bean);
}
beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());
}
}
@Autowired
private Service[] serviceArray;
list类型
与数组类型类似
DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"), true);
if (dd2.getDependencyType() == List.class) {
Class<?> resolve = dd2.getResolvableType().getGeneric().resolve();
System.out.println(resolve);
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);
List<Object> beanList = new ArrayList<>();
for (String name : names) {
System.out.println(name);
Object o = dd2.resolveCandidate(name, resolve, beanFactory);
beanList.add(o);
}
}
@Autowired
private List<Service> serviceList;
ApplicationContext
DependencyDescriptor dd3 = new DependencyDescriptor(Target.class.getDeclaredField("applicationContext"), true);
Field resolvableDependencies = DefaultListableBeanFactory.class.getDeclaredField("resolvableDependencies");
resolvableDependencies.setAccessible(true);
Map<Class<?>, Object> dependencies = (Map<Class<?>, Object>) resolvableDependencies.get(beanFactory);
/*dependencies.forEach((k, v) -> {
System.out.println("key:" + k + "value:" + v);
});*/
for (Map.Entry<Class<?>, Object> entry : dependencies.entrySet()) {
dependencies.get(ConfigurableApplicationContext.class);
if (entry.getKey().isAssignableFrom(ConfigurableApplicationContext.class)) {
System.out.println(entry.getValue());
break;
}
}
@Autowired
private ConfigurableApplicationContext applicationContext;
泛型
DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"), true);
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
Class<?> type = dd4.getDependencyType();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
//对比beanDefinition与DependencyDescriptor的泛型做比较
if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd, name), dd4)) {
System.out.println(name);
}
}
interface Dao<T> {
}
@Component("dao1")
static class Dao1 implements Dao<Student> {
}
@Component("dao2")
static class Dao2 implements Dao<Teacher> {
}
@Qualifier
根据名字注入
DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"), true);
Class<?> dependencyType = dd5.getDependencyType();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, dependencyType)) {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd, name), dd5)) {
System.out.println(name);
System.out.println(dd5.resolveCandidate(name, dependencyType, beanFactory));
}
}
@Autowired
@Qualifier("service2")
private Service service;
interface Service {
}
@Component("service1")
static class Service1 implements Service {
}
@Component("service2")
static class Service2 implements Service {
}
@Component("service3")
static class Service3 implements Service {
}
@Primary
优先查找
static class Target1 {
@Autowired
private Service service;
}
static class Target2 {
@Autowired
private Service service3;
}
interface Service {
}
@Component("service1")
static class Service1 implements Service {
}
@Component("service2")
@Primary
static class Service2 implements Service {
}
@Component("service3")
static class Service3 implements Service {
}
private static void testPrimary(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd = new DependencyDescriptor(Target1.class.getDeclaredField("service"), false);
Class<?> type = dd.getDependencyType();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
if (beanFactory.getMergedBeanDefinition(name).isPrimary()) {
System.out.println(name);
System.out.println(dd.resolveCandidate(name, type, beanFactory));
}
}
}
Default
默认根据名字进行查找
private static void testDefault(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd = new DependencyDescriptor(Target2.class.getDeclaredField("service3"), false);
Class<?> type = dd.getDependencyType();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
if (name.equals(dd.getDependencyName())) {
System.out.println(name);
System.out.println(dd.resolveCandidate(name, type, beanFactory));
}
}
}
发布监听
当我们的系统需要异步,除了使用mq中间件以为我们还可以通过,使用springboot事件监听器和发布器来完成,下面就是一个使用它的案例,不过他的缺点就是对于分布式的支持并不是很好
@Configuration
public class A41_1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A41_1.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
static class MyEvent extends ApplicationEvent{
public MyEvent(Object source) {
super(source);
}
}
@Component
@Slf4j
static class MyService {
@Autowired
private ApplicationEventPublisher publisher;
public void doBusiness(){
log.info("主线业务");
publisher.publishEvent(new MyEvent("myService.doBusiness"));
// log.info("发送短信");
// log.info("发送邮件");
}
}
@Component
@Slf4j
static class smsApplicationListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.info("发送短信");
}
}
@Component
@Slf4j
static class emailApplicationListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.info("发送邮件");
}
}
}
事件监听器
自定义一个监听器
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyListener {
}
配置一个SmartInitializingSingleton,使他对于listener进行解析
@Bean
public SmartInitializingSingleton smartInitializingSingleton(ConfigurableApplicationContext context) {
return () -> {
//获取任意类型的bean加了MyListener注解解析他
for (String name : context.getBeanDefinitionNames()) {
Object bean = context.getBean(name);
for (Method method : bean.getClass().getMethods()) {
if (method.isAnnotationPresent(MyListener.class)) {
ApplicationListener<ApplicationEvent> listener = event -> {
//监听器方法需要的类型
Class<?> eventType = method.getParameterTypes()[0];
//筛选事件类型
if(eventType.isAssignableFrom(event.getClass())){
try {
method.invoke(bean, event);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
};
//加入到context
context.addApplicationListener(listener);
}
}
}
};
}
事件发布器
@Bean
public ApplicationEventMulticaster applicationEventMulticaster(ConfigurableApplicationContext applicationContext, ThreadPoolTaskExecutor executor) {
return new AbstractApplicationEventMulticaster() {
private List<GenericApplicationListener> listeners = new ArrayList<>();
@Override
public void addApplicationListenerBean(String listenerBeanName) {
log.info(listenerBeanName);
ApplicationListener bean = applicationContext.getBean(listenerBeanName, ApplicationListener.class);
//获取事件类型
ResolvableType type = ResolvableType.forClass(bean.getClass()).getInterfaces()[0].getGeneric();
log.info(String.valueOf(type));
//将原始的listener封装为支持类型检查的listener
GenericApplicationListener genericApplicationListener = new GenericApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
executor.submit(()-> bean.onApplicationEvent(event));
}
//是否支持事件类型
@Override
public boolean supportsEventType(ResolvableType eventType) {
return type.isAssignableFrom(eventType);
}
};
listeners.add(genericApplicationListener);
}
@Override
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
listeners.forEach(i -> {
if (i.supportsEventType(ResolvableType.forClass(event.getClass()))) {
i.onApplicationEvent(event);
}
});
}
};
}
添加一个线程池
@Bean
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
return executor;
}