微服务在哪里springboot中下onApplicationEvent⽅法被执⾏两次问题分析及解决⼀、背景
1. 项⽬中使⽤的技术栈是 spring cloud + spring boot 构建的分布式项⽬。
2. 其中⼀个微服务下创建了⼀个监听者,⽤于项⽬启动时从 Apollo 中获取 kafka 的配置信息(地址、topic、等⼀些基本配置),然后
利⽤加载的配置初始化 kafka。代码如下:
3. 现在出现⼀个问题,项⽬启动的时候 onApplicationEvent() ⽅法每次都会执⾏两遍,kafka 也会初始化两遍,导致业务中发送
kafka 时会发送两遍同样的 kafka。
⼆、分析
1. 可以在 onApplicationEvent() ⽅法中添加图⼀中的各种参数,图⼆可以查看打印出来的内容。 注意:
获取各种参数的语句可能会引
起空指针异常⽐如 “ApplicationContext().getParent().getParent()”,可以根据⾃⼰的项⽬修改。
图⼀:
图⼆:
2. 查看打印的两块内容中的“容器中参数 getSources:”内容,发现下⾯容器中的 “class
3. 于是⽤快捷键 Ctrl+N 搜索该类,发现它是因为在 pom ⽂件引⼊了 该依赖< artifactId >spring-cloud-starter-bus-amqp</
artifactId> 项⽬启动时这个依赖包就会启动⼀个新的容器。如果在 pom ⽂件中把该依赖去掉,再启动项⽬会发现
onApplicationEvent() ⽅法只加载⼀次了,即上⾯的容器没有被加载。但显然这不是解决问题的⽅法,因为项⽬中要⽤到这个功能,如果项⽬中没有⽤到这个依赖可以考虑去掉,也就解决了问题。
4. 再分析图⼆中的另⼀参数 “容器中参数 getApplicationName: ”。上⾯容器打印的是空字符串,下⾯容器打印的是“/demo”,
其实下⾯容器中的“/demo”就是配置⽂件即 yml 中 t-path: 的值,如果 yml 中没有配置则会同上⾯容器⼀样显⽰空字符串。
5. 分析图⼆中的参数 “容器中参数 getParent:” 和 “容器中参数 Parent:” 可以看出,其实是三个容器进⾏了嵌
套。上⾯那个容器有两个⽗容器,下⾯那个容器有⼀个⽗容器。⾄于为什么出现这种情况可以⾃⼰看看源码、资料,或者有⼤佬评论区分享⼀下。
三、解决
根据上⾯的分析可以提供以下⼏种解决⽅案。
1. 根据分析 3,可以看⼀下引起 onApplicationEvent() ⽅法被执⾏两次的依赖包项⽬中有没有⽤到,没有的话删除依赖就能解决问
题。如果⽤到了再考虑下⾯的⽅法。
2. 根据分析 4,可以通过下⾯⽅法解决。前提是配置⽂件中要有该配置。
@Component
public class DataInitializerListener implements ApplicationListener<ApplicationReadyEvent>{
@Override
public void onApplicationEvent(ApplicationReadyEvent event){
//思路:只有加载配置⽂件的容器启动时才执⾏该⽅法,通过下⾯的判断排除掉别的容器。
if("/demo".ApplicationContext().getApplicationName())){
//功能代码
System.out.println("kafka 配置");
}
}
}
3. 根据分析 5,可以通过下⾯⽅法解决,这也是⽹上最常见的⽅法。
@Component
public class DataInitializerListener implements ApplicationListener<ApplicationReadyEvent>{
@Override
public void onApplicationEvent(ApplicationReadyEvent event){
//思路:既然是多个容器嵌套,那么只让最外层的容器即⽗容器启动时执⾏该⽅法,其他的容器排除掉
ApplicationContext().getParent().getParent()==null){
//本⼈的项⽬中是三个容器嵌套,需要两层⽗容器,如果是两个容器嵌套只需要⼀层。判断条件需要改为:
// ApplicationContext().getParent() == null){
//功能代码
System.out.println("kafka 配置");
}
}
}
4. 测试⼀下就会发现,类只加载了⼀遍,⽅法执⾏了两次,因此还有⼀种⽅法。
@Component
public class DataInitializerListener implements ApplicationListener<ApplicationReadyEvent>{
private boolean flag =false;
@Override
public void onApplicationEvent(ApplicationReadyEvent event){
//思路:加⼀个标记,第⼀个容器启动时不执⾏此⽅法,第⼆个容器启动时才执⾏。
if(flag){
//功能代码
System.out.println("kafka 配置");
}else{
flag =true;
}
}
}
四、最后
1. 解决完启动问题后还要测试⼀下,项⽬运⾏过程中触发监听者中的事件 onApplicationEvent() 内的功能代码还能否执⾏到。
2. 这⼏个解决的⽅案都是对 onApplicationEvent() ⽅法进⾏操作,如果还有别的⽅法欢迎讨论。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。