SpringBoot启动自动执行的几种方式
一、实现ApplicationRunner接口
实现ApplicationRunner接口的run方法,其中重写方法的参数是启动命令中的Program arguments参数,该实现是在Spring容器启动之后通过调用callRunners()方法执行,会从Spring容器中获取所有的ApplicationRunner实现类与CommandLineRunner实现类,并且排序后执行,也就是执行该方法的时候可以获取Spring容器中的bean,也可以实现多个,通过注解@Order或者实现以下接口之一(Ordered,PriorityOrdered)自定义顺序。该方法的执行和CommandLineRunner实现类的方法执行在一个线程中,因此最好不要出现死循环。
@Component
public class MyApplicationRunner implements ApplicationRunner {
private static Logger logger = LoggerFactory.getLogger(MyApplicationRunner.class);
@Override
public void run(ApplicationArguments args) throws Exception {
logger.info("开始执行ApplicationRunner接口实现类的run方法");
for (String sourceArg : args.getSourceArgs()) {
logger.info("sourceArge:{}",sourceArg);
}
Set<String> optionNames = args.getOptionNames();
optionNames.forEach(x->{
logger.info("option:{}",x);
});
}
}
callRunners()方法源码如下:
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
Iterator var4 = (new LinkedHashSet(runners)).iterator();
while(var4.hasNext()) {
Object runner = var4.next();
if (runner instanceof ApplicationRunner) {
this.callRunner((ApplicationRunner)runner, args);
}
if (runner instanceof CommandLineRunner) {
this.callRunner((CommandLineRunner)runner, args);
}
}
}
二、实现CommandLineRunner接口
实现CommandLineRunner接口的run方法传入的参数是"key=value"的字符串,也是Program arguments参数,也可以通过注解@Order进行排序。通过上面callRunner方法的源码可以看出来.
@Component
public class MyCommondLineRunner implements CommandLineRunner {
private static Logger logger = LoggerFactory.getLogger(MyCommondLineRunner.class);
@Override
public void run(String... args) throws Exception {
logger.info("实现了CommandLineRunner的run方法");
for (String arg : args) {
logger.info("arg:{}",arg);
}
}
}
三、实现ServletContextAware接口
实现ServletContextAware接口的setServletContext方法,它是Spring中就已经存在的接口。
@Component
public class MyServletContextAware implements ServletContextAware {
private static Logger logger = LoggerFactory.getLogger(MyServletContextAware.class);
@Override
public void setServletContext(ServletContext servletContext) {
logger.info("实现了MyServletContextAware的setServletContext方法");
}
}
具体在使用中,在加载Bean之前(初始化Bean的准备准备工作时)就会将servletContext放入该对象中,但是通过执行测试执行该方法时bean已经初始化,故可以使用依赖注入。bean在执行实例方法调用的时候才会被加载。
四、实现ServletContextListener接口
实现ServletContextListener的contextInitialized方法,在ServletContextListener实现类之前执行,ServletContext初始化之后执行,用于ServletContext对象的生命周期监听,可以是实现contextDestroyed()方法用于ServletContext对象释放后执行。也可以进行依赖注入。
@Component
public class MyServletContextListener implements ServletContextListener {
private static Logger logger = LoggerFactory.getLogger(MyServletContextListener.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
logger.info("实现了ServletContextListeneri接口的contextInitialized方法");
}
}
五、实现ApplicationListener接口
实现ApplicationListener接口的onApplicationEvent方法,
@Component
public class MyApplicationLisenter implements ApplicationListener<ContextRefreshedEvent> {
private static Logger logger = LoggerFactory.getLogger(MyApplicationLisenter.class);
@Override
public void onApplicationEvent(ContextRefreshedEvent e) {
logger.info("实现了ApplicationListener的onApplicationEvent方法");
}
}
Spring内部有一下监听事件,如果需要自定义事件需要实现ApplicationEvent抽象类。
类名 | 描述 |
ContextRefreshedEvent | ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用 |
ContextStartedEvent | 当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。 |
ContextStoppedEvent | 当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。 |
ContextClosedEvent | 当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。 |
RequestHandledEvent | 这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。 |
自定义方法触发时间如下:
public class SpringTest {
public static void main(String args[]){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//创建一个ApplicationEvent对象
EmailEvent event = new EmailEvent("hello","abc@163.com","This is a test");
//主动触发该事件
context.publishEvent(event);
}
}
六、注解@PostConstruct与Spring容器中的static方法
添加了注解@PostConstruct的方法会在启动时被执行,Bean在被初始化之后就会执行带有@PostConstruct的方法,该方法只会被服务器执行一次,该注解执行用在返回值为void且没有传参的方法,这是JSR-250的规范,Spring容器中的static方法也会在加载该类的时候执行。
@Component
public class MyPostConstruct {
private static Logger logger = LoggerFactory.getLogger(MyPostConstruct.class);
static {
logger.info("MyPostConstruct静态代码块");
}
@PostConstruct
public void hhhh() {
logger.info("注解@PostConstruct所在的方法");
}
}