springboot 初始化serviceImpl注入对象
背景
今天遇到个需求是:公司是炼钢相关的项目,点位数据上来后放入kafka中,kafka要对数据进行处理,根据配置的点位值判断点位是否正常。
经历
看到这个需求,开始是这样实现的(然后每次修改了配置,就置空一下这个map)
public static Map<String, EnergyInstrumentLogDTO> monitorConfigMap = null
//消费方法
private void consumerMsg(Object msg){
if(monitorConfigMap == null){
//初始化加载
}
//消费消息
}
有个同事看了我写的,觉得会发生线程安全问题。仔细一想是觉得有点不对劲,于是乎就修改成了下面这样
private static Map<String, EnergyInstrumentLogDTO> monitorConfigMap = new HashMap<>();
@Autowired
private LogConfigMapper logConfigMapper;
private ConsumerPointDataMsg(){
initMonitorConfig();
}
public void refreshMonitorMap() {
//此处会调用数据库日志配置logConfigMapper
initMonitorConfig();
}
这样就有一个问题了,类构造器中初始化时要调用logConfigMapper,此刻这个mapper的实体是null的。以上就是问题产生的前因,下面继续讲述后果,直接上干货。
解决方案
- 使用构造器注入方式(可能会引发A启动要依赖B,B启动要依赖A导致报错–懒加载避免)
- 使用ApplicationContext的bean管理
- 实现InitializingBean接口,重写afterPropertiesSet方法。该方法是设置属性后执行
- 构造方法注入
构造器注入
@Component
public class PostConstructTest1 {
@Autowired
PostConstructTest2 postConstructTest2;
public PostConstructTest1() {
//postConstructTest2.test();
}
@PostConstruct
public void init() {
// todo sth
}
}
Bean初始化时的执行顺序: 构造方法 -> @Autowired -> @PostConstruct
2.ApplicationContext
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
//使用时
private void initMonitorConfig(){
LogConfigMapper mapper = ApplicationContextProvider.getBean(LogConfigMapper.class);
}
此种方案不太建议使用,因为有点开挂的感觉,直接到spring容器中去获取bean
3.重写afterPropertiesSet
@Component
@Slf4j
public class ConsumerPointDataMsg implements InitializingBean {
private static Map<String, EnergyInstrumentLogDTO> monitorConfigMap = new HashMap<>();
@Autowired
private LogConfigMapper logConfigMapper;
@Override
public void afterPropertiesSet() throws Exception {
initMonitorConfig();
}
}
4. 构造方法注入
@Configuration
public class XxlJobConfig {
private final AddressServiceImpl addressService;
public XxlJobConfig(AddressServiceImpl addressService) {
this.addressService = addressService;
}
//直接调用
addressService.serviceUrl("XXL-JOB-ADMIN")
}