问题描述:
经常遇到这样的场景:希望容器启动的时候,进行一些初始化等操作。一般的做法就是通过Spring的bean set方式或者@PostConstruct注解来解决;
很多人使用@ PostConstruct或者@Component的时候,经常出现Spring容器里面的bean(尤其是数据库操作相关的bean)还没有启动完全,自己需要初始化的bean代码已经调用。
下面是一个自己使用的方法,也许不是最优的方案,但是是经过了实践考验的。
编写所有启动类的接口
这一步可以省略,因为我要实现的是,容器启动的时候,自动扫描所有实现了自定义启动接口的实例,并调用初始化方法。
package com.chz.apps.common.component;
/**
* 自启动接口类,容器启动完成后,自动调用启动方法
*/
public interface IAutoStartPlugin {
/**
* 启动
*/
void start();
}
编写容器启动bean
package com.chz.component.basic.listener;
import com.chz.apps.common.component.IAutoStartPlugin;
import com.chz.component.basic.configure.SpringContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
private static Boolean loaded = false;//启动标记,确保只启动过一次
@Autowired
private DicPlugin dicPlugin;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(event.getApplicationContext().getParent() != null && !loaded){
Map<String,IAutoStartPlugin> allPlugin = SpringContextHolder.getApplicationContext().getBeansOfType(IAutoStartPlugin.class);
if(allPlugin != null || allPlugin.size() > 0){
for (Map.Entry<String,IAutoStartPlugin> row : allPlugin.entrySet()) {
row.getValue().start();//调用启动类
}
}
loaded = true;
}
}
}
添加ApplicationContext.xml配置
在文件的最后加上如下配置:
<bean id="afterStartupListener" class="com.chz.component.basic.listener.StartupListener" /><!-- 启动容器后执行的方法 -->
编写接口实现类即可
剩下的工作就与业务有关了,直接编写接口实现类,程序在启动的时候,加载完Spring容器后,会调用上面的StartupListener类进行初始化,通过SpringContextHolder(需要预先配置)获取所有实现了接口的bean,依次调用bean里面的start方法。