Spring启动前后自动执行代码
有些Spring项目在启动的时候需要预加载一些资源,有以下方式:
一、启动前执行
1、Java类加载阶段
①:static变量
在类加载的准备阶段为static变量分配内存并设置类初始值(数据字段类型的默认值)
在类加载的初始化阶段为static变量赋定义的值
②:static代码块
在类加载的初始化阶段执行静态代码块
2、监听器
自定义监听器实现ApplicationListener接口,监听以下事件
容器开始启动 | ApplicationStartingEvent |
二、启动中执行
1、bean实例化阶段
①:构造代码块
每次创建对象时执行一次,优先于构造方法执行
②:构造方法
每次创建对象时执行一次
2、Spring bean初始化阶段
①:如果bean实现了BeanNameAware接口,Spring将调用setBeanName()方法将bean的ID传递入
②:如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
③:如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传进来
④:@PostConstruct 标注的方法,在执行完构造器之后初始化对象时执行
⑤:afterPropertiesSet方法,若bean实现了InitializingBean接口,接着执行此初始化方法
⑥:initMethod,@Bean注解上自定义的初始化方法
3、Spring监听器
自定义监听器实现ApplicationListener接口,监听以下事件
在环境(environment)准备完成,容器创建之前 | ApplicationEnvironmentPreparedEvent |
容器创建完成,并且准备完成,资源加载之前 | ApplicationContextInitializedEvent |
容器加载完成,刷新之前 | ApplicationPreparedEvent |
三、启动后执行
1、Spring监听器
自定义监听器实现ApplicationListener接口,监听以下事件
容器启动完成 | ApplicationStartedEvent |
容器运行 | ApplicationReadyEvent |
容器启动失败 | ApplicationFailedEvent |
2、CommandLineRunner 和 ApplicationRunner
两个接口都是在ApplicationStartedEvent事件之后执行 ,用于在Spring容器启动完成后执行一些功能。
对应下图,callRunners方法:
先执行 ApplicationRunner 后执行 CommandLineRunner
两个接口都有一个run方法,区别在于run方法的入参不同
CommandLineRunner | void run(String... args) throws Exception; |
ApplicationRunner | void run(ApplicationArguments args) throws Exception; |
①:CommandLineRunner,接口,用于指示当一个bean被包含在一个SpringApplication中时应该运行它。可以在同一个应用程序上下文中定义多个CommandLineRunner bean,并且可以使用ordered接口或@Order注释进行排序
②:ApplicationRunner,接口,用于指示当一个bean被包含在一个SpringApplication中时应该运行它。可以在同一个应用程序上下文中定义多个ApplicationRunner bean,并且可以使用ordered接口或@Order注释进行排序
使用:自定义类实现CommandLineRunner或ApplicationRunner接口,在实现的run()方法里执行想要自动执行的代码。
Order注解:
当有多个类实现了CommandLineRunner和ApplicationRunner接口时,可以通过在类上添加@Order注解来设定运行顺序。
示例:
SpringApplicationStartedListener:
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* 监听当容器启动后,做一些数据预热工作
*/
@Component
public class SpringApplicationStartedListener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
// 加载数据到缓存 ...
}
}
CacheRunner:
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* 容器启动后预热缓存
*/
@Component
public class CacheRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// 预热缓存...
}
}
END.