SpringBoot项目资源初始化加载的几种方式
一、问题
日常业务模块开发的过程中,难免会需要做一些全局任务、缓存、线程等的初始化工作,那么如何做呢?方法有很多,但具体又要怎么选择呢?
二、资源初始化
1、既然我们要做资源的初始化,那么就要了解一下springboot启动过程。
按照前面的分析,Spring-boot容器启动流程总体可划分为2部分:
执行注解:扫描指定范围下的bean、载入自动配置类对应的bean加载到IOC容器。
man方法中具体SpringAppliocation.run(),全流程贯穿SpringApplicationEvent(经典的spring事件驱动模型),有6个子类:
ApplicationFailedEvent.class
ApplicationPreparedEvent.class
ApplicationReadyEvent.class
ApplicationStartedEvent.class
ApplicationStartingEvent.class
SpringApplicationEvent.class
2、CommandLineRunner和ApplicationRunner
由上可知,我们只要实现这两个接口中的任何一个就可以完成资源初始化任务,可以看到它们的加载是在容器完全启动之前。
区别是:前者的run方法参数是String...args,直接传入字符串,后者的参数是ApplicationArguments,对参数进行了封装。
功能上基本是一样的。同时我们也可以使用@Order注解来实现资源加载的顺序,值越小,优先级越高。实例如下:
@Component @Order(1) public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("...init resources by implements CommandLineRunner"); } } @Component @Order(2) public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments applicationArguments) throws Exception { System.out.println("...init resources by implements ApplicationRunner"); } }
3、@PostConstruct
在具体Bean的实例化过程中执行,@PostConstruct注解标记的方法,会在构造方法之后执行,
顺序:Constructor > @Autowired > @PostConstruct > 静态方法,
所以这个注解就避免了一些需要在构造方法里使用依赖组件的尴尬(对应的还有@PreDestroy注解,在对象消亡之前执行,原理基本一样的)。
使用特点如下:
只有一个非静态方法能使用此注解
被注解的方法不得有任何参数
被注解的方法返回值必须为void
被注解方法不得抛出已检查异常
此方法只会被执行一次
4、InitializingBean
InitializingBean 是 Spring 提供的一个接口,只包含一个方法afterPropertiesSet()。
凡是实现了该接口的类,当其对应的 Bean交由Spring管理后,当其必要的属性全部设置完成后,Spring会调用该Bean的afterPropertiesSet()方法。
在Bean在实例化过程中执执行顺序为:Constructor > @PostConstruct > InitializingBean > init-method
public class InitSequenceBean implements InitializingBean { public InitSequenceBean() { System.out.println("InitSequenceBean: constructor"); } @PostConstruct public void postConstruct() { System.out.println("InitSequenceBean: postConstruct"); } public void initMethod() { System.out.println("InitSequenceBean: init-method"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("InitSequenceBean: afterPropertiesSet"); } }
5、ApplicationListener
ApplicationListener 就是spring的监听器,能够用来监听事件,属于典型的观察者模式。如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将会自动被触发。这种事件机制都必须要程序显式的触发。其中spring有一些内置的事件,当完成某种操作时会发出某些事件动作。比如监听ContextRefreshedEvent事件,当所有的bean都初始化完成并被成功装载后会触发该事件,实现ApplicationListener接口可以收到监听动作,然后可以写自己的逻辑。同样事件可以自定义、监听也可以自定义,完全根据自己的业务逻辑来处理。所以也能做到资源的初始化加载!
@Component public class DataSourceInitListener implements ApplicationListener<ContextRefreshedEvent> { //ContextRefreshedEvent为启动事件 private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceInitListener.class); @Autowired private SystemConfigService systemConfigService; @Autowired private ItemService itemService; @Autowired private SystemResultService systemResultService; @Override public void onApplicationEvent(ContextRefreshedEvent event) { //判断是否执行过,执行过则不再执行 if(event.getApplicationContext().getParent() == null) { LOGGER.info("初始化systemConfig数据"); systemConfigService.initConfig(); LOGGER.info("初始化返回消息数据"); systemResultService.initResult(); LOGGER.info("系统初始化结束..........."); } } }