ApplicationListener在使用过程中可以监听某一事件的发生,可以做出相应的处理,这个方式不常用,但是在特殊情况下面还是有用的。
在一些业务场景中,当容器初始化完成之后,需要处理一些操作,比如一些数据的加载、初始化缓存、特定任务的注册等等。这个时候我们就可以使用Spring提供的ApplicationListener来进行操作。
本文以在Spring boot下的使用为例来进行说明。首先,需要实现ApplicationListener接口并实现onApplicationEvent方法。把需要处理的操作放在onApplicationEvent中进行处理:
此处使用Spring boot来进行操作,没有出现二次调用的问题。在使用传统的application.xml和project-servlet.xml配置中会出现二次调用的问题。主要原因是初始化root容器之后,会初始化project-servlet.xml对应的子容器。我们需要的是只执行一遍即可。那么上面打印父容器的代码用来进行判断排除子容器即可。在业务处理之前添加如下判断:
if(contextRefreshedEvent.getApplicationContext().getParent() != null){
return;
}if(contextRefreshedEvent.getApplicationContext().getParent() != null){
return;
}
这样其他容器的初始化就会直接返回,而父容器(Parent为null的容器)启动时将会执行相应的业务操作。
在spring中InitializingBean接口也提供了类似的功能,只不过它进行操作的时机是在所有bean都被实例化之后才进行调用。根据不同的业务场景和需求,可选择不同的方案来实现。
1、pom文件
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.7.RELEASE
com.mqm501
springboot-init
0.0.1-SNAPSHOT
springboot-init
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.0
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
com.alibaba
druid
1.1.0
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.0
org.springframework.boot
spring-boot-maven-plugin
2、字典表配置文件:
{
"age_segment":{
"0":"0-17",
"1":"18-25",
"2":"26-35",
"3":"36-45",
"4":"46-55",
"5":"56-"
},
"sex_type":{
"0":"男",
"1":"女",
"2":"不详"
},
"profession_type":{
"1":"一级",
"2":"二级",
"3":"三级",
"4":"四级",
"5":"五级",
"6":"六级",
"7":"其他"
},
"marry_type":{
"0":"未婚",
"1":"已婚",
"2":"丧偶",
"3":"分居",
"4":"再婚",
"5":"同居",
"6":"离婚",
"9":"其他"
},
"buyer_flag":{
"1":"是",
"2":"否"
}
}
3、读取字典配置文件
package com.hlt.sundata.httpglobal.init;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils;
/**
* Project: sundata Package: com.hlt.sundata.httpglobal.bean
* Create Time: 2019年08月30日 00:56
* @author: qingmei.meng
* Description:
**/
@Service("dictInit")
public class DictInit {
/**存放系统参数*/
public static HashMap dictMap = new HashMap();
/**参数初始化工作*/
public void start() {
injectDictConfig();
}
/**读取字典表 */
private void injectDictConfig() {
System.out.println("-------injectDictConfigByDb start-------------------");
try {
String filename = "static/data/dic.json";
FileInputStream inputStream = null;
File file = new File(filename);
if (!file.exists()) { // 如果同级目录没有,则去config下面找
file = new File("config/"+filename);
}
Resource resource = new FileSystemResource(file);
if (!resource.exists()) { //config目录下还是找不到,那就直接用classpath下的
file = ResourceUtils.getFile("classpath:"+filename);
}
inputStream = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charsets.UTF_8));
String var = FileCopyUtils.copyToString(reader);
String newVar = var.replaceAll("\\s*","");
inputStream.close();
System.out.println(newVar);
ObjectMapper mapper = new ObjectMapper();
try {
dictMap = mapper.readValue(newVar, new TypeReference>() {});
} catch (Exception e) {
e.printStackTrace();
System.out.println("-------injectDictConfig to json error-------------------");
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("-------injectDictConfig file error-------------------");
}
System.out.println("-------injectDictConfig success-------------------");
}
}
4、springboot初始化加载
package com.hlt.sundata.httpglobal.init;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* Project: sundata Package: com.hlt.sundata.httpglobal.util
* Create Time: 2019年08月30日 00:53
* @author: qingmei.meng
* Description:
**/
@Component("BeanDefineConfigue")
public class StartLoader implements ApplicationListener {
@Autowired
private DictInit dictInit;
//当一个ApplicationContext被初始化或刷新触发
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("START:spring初始化开始======================>");
if (event.getApplicationContext().getParent() == null) {//root application context 没有parent,他就是老大.
System.out.println("启动projectInit的start方法进行参数的初始化======================>");
dictInit.start();
} else {
//为什么会执行两次:请参考博文:http://www.cnblogs.com/yucongblog/p/5437744.html
System.out.println("spring初始化时,执行onApplicationEvent:event.getApplicationContext().getParent() != null======================>");
}
System.out.println("spring初始化完毕======================>");
}
}
5、启动后成功加载
START:spring初始化开始======================>
启动projectInit的start方法进行参数的初始化======================>
-------injectDictConfigByDb start-------------------
{"age_segment":{"0":"0-17","1":"18-25","2":"26-35","3":"36-45","4":"46-55","5":"56-"},"sex_type":{"0":"男","1":"女","2":"不详"},"profession_type":{"1":"一级","2":"二级","3":"三级","4":"四级","5":"五级","6":"六级","7":"其他"},"marry_type":{"0":"未婚","1":"已婚","2":"丧偶","3":"分居","4":"再婚","5":"同居","6":"离婚","9":"其他"},"buyer_flag":{"1":"是","2":"否"}}
-------injectDictConfig success-------------------
spring初始化完毕======================>