简介
在SpringBoot中我们有时候需要让项目在启动时自动执行某个方法。本文介绍如何在启动时执行,方案很全,且都有实例。
法1:实现ApplicationRunner接口(推荐)
继承Application接口后项目启动时会按照执行顺序执行run方法。
定义多个applicationrunner bean时,可以用注解@Order或者实现Ordered接口对其进行排序。
自动执行的方法
@Component
@Order(1)
public class MyTest implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("this is ApplicationRunner:run");
}
}
实现接口Ordered进行排序的方式如下:
@Component
public class MyTest implements ApplicationRunner, Ordered {
@Override
public int getOrder() {
return 1;
}
@Override
public void run(ApplicationArguments args) {
System.out.println("this is run");
}
}
传递参数示例
–getOptionNames()方法可以得到foo这样的key的集合。
–getOptionValues(String name)方法可以得到bar这样的集合的value
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class MyApplicationRunner implements ApplicationRunner{
@Override
public void run(ApplicationArguments args) {
System.out.println("===MyApplicationRunner===" + Arrays.asList(args.getSourceArgs()));
System.out.println("===getOptionNames========" + args.getOptionNames());
System.out.println("===getOptionValues=======" + args.getOptionValues("foo"));
System.out.println("===getOptionValues=======" + args.getOptionValues("developer.name"));
}
}
配置参数启动:
--foo=bar --developer.name=xiao.qiang
运行结果:
===MyApplicationRunner===[--foo=bar, --developer.name=xiao.qiang] ===getOptionNames========[foo, developer.name] ===getOptionValues=======[bar] ===getOptionValues=======[xiao.qiang]
法2:实现CommandLineRunner接口(推荐)
CommandLineRunner和ApplicationRunner的作用是相同的。不同点在于,前者的run方法参数是String…args,直接传入字符串后者的参数是ApplicationArguments,对参数进行了封装。这些参数是启动spring boot程序时传给main()方法的。
ApplicationArguments是对参数(main方法)做了进一步的处理,可以解析–name=value的,我们就可以通过name来获取value,而CommandLineRunner只是获取–name=value而不解析。
自动运行的方法
@Component
@Order(value = 1)
public class MyTest implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("this is CommandLineRunner");
}
}
传递参数示例
import java.util.Arrays;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class CommandLineRunnerBean implements CommandLineRunner {
@Override
public void run(String... args) {
String strArgs = Arrays.stream(args).collect(Collectors.joining("|"));
System.out.println("Application started with arguments:" + strArgs);
}
}
使用带有参数的可执行jar运行程序。spring-boot-demo-0.0.1-SNAPSHOT.jar为生成的jar文件。执行命令如下:
java -jar spring-boot-demo-0.0.1-SNAPSHOT.jar data1 data2 data3
输出结果
Application started with arguments:data1|data2|data3
法3:实现ApplicationListener接口(推荐)
@Component
public class MyTest implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
if (applicationEvent instanceof ApplicationStartedEvent) {
System.out.println("容器启动完毕");
}
}
}
结果
2024-03-11 18:56:51.379 INFO 30140 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.55] 2024-03-11 18:56:51.447 INFO 30140 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-03-11 18:56:51.447 INFO 30140 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 943 ms 2024-03-11 18:56:51.945 INFO 30140 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2024-03-11 18:56:52.103 INFO 30140 --- [ main] com.knife.example.DemoApplication : Started DemoApplication in 2.017 seconds (JVM running for 2.705) 容器启动完毕
法4:静态方法/@PostConstruct
静态代码块会在依赖注入后自动执行,并优先执行
@Postcontruct在依赖注入完成后自动调用
@Component
public class Test2 {
static{
System.out.println("this is static");
}
@PostConstruct
public void test(){
System.out.println("this is PostConstruct");
}
}
运行结果
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.7.RELEASE) 2020-05-14 21:41:28.713 INFO 9676 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on liu-PC with PID 9676 (E:\work\idea_proj\SpringBoot-url\target\classes started by liu in E:\work\idea_proj\SpringBoot-url) 2020-05-14 21:41:28.715 INFO 9676 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default this is static this is PostConstruct 2020-05-14 21:41:30.281 INFO 9676 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler' 2020-05-14 21:41:30.321 INFO 9676 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 2.579 seconds (JVM running for 5.488) 2020-05-14 21:41:30.325 INFO 9676 --- [extShutdownHook] o.s.s.c.ThreadPoolTaskScheduler : Shutting down ExecutorService 'taskScheduler'
法5:实现InitializingBean接口
@Component
public class MyTest implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
}
法6:提供initMethod
@Configuration
public class MyTest {
@Bean(name = "myUser", initMethod = "initUser")
public Object myUser() {
return new User();
}
public static class User {
public void initUser() {
System.out.println("initMethod");
}
}
}
法7:在启动类的main里边进行
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
System.out.println("before main run");
SpringApplication.run(DemoApplication.class, args);
System.out.println("after main run");
}
}
运行结果
before main run . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.2.7.RELEASE) 2020-05-14 22:07:16.981 INFO 10644 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on liu-PC with PID 10644 (E:\work\idea_proj\SpringBoot-url\target\classes started by liu in E:\work\idea_proj\SpringBoot-url) 2020-05-14 22:07:16.985 INFO 10644 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default 2020-05-14 22:07:18.631 INFO 10644 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-05-14 22:07:18.641 INFO 10644 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-05-14 22:07:18.641 INFO 10644 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.34] 2020-05-14 22:07:18.748 INFO 10644 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-05-14 22:07:18.748 INFO 10644 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1696 ms 2020-05-14 22:07:18.942 INFO 10644 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-05-14 22:07:19.074 INFO 10644 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler' 2020-05-14 22:07:19.130 INFO 10644 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-05-14 22:07:19.133 INFO 10644 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 2.806 seconds (JVM running for 4.439) after main run
法8:@EnableScheduling
启动类
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
测试类
@Component
public class MyTest{
@Scheduled(cron = "0/5 * * * * ?")
public void test(){
System.out.println("this is Scheduled");
}
}
这样会每5秒打印一次。
法9:实现ApplicationListener接口
onApplicationEvent属于应用层的事件。
@Component
public class MyTest implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("ApplicationListener");
}
}
备注:SpringBoot提供了很多启动流程的事件(ApplicationEvent的子类),比如:
- ApplicationStartingEvent
- ApplicationStartedEvent
- ApplicationFailedEvent
- ApplicationReadyEvent
- ContextRefreshedEvent
- ContextStartedEvent
- ContextClosedEvent
- ContextStoppedEvent
- 等等
法10:实现ServletContextAware接口
实现ServletContextAware接口并重写其setServletContext方法。
setServletContext方法会在填充完普通Bean的属性,但是还没有进行Bean的初始化之前执行。类似于initializingbean的afterpropertiesset或自定义init方法的回调。
@Component
public class Mytest implements ServletContextAware {
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("this is ServletContextAware:setServletContext");
}
}
法11:实现ServletContextListener接口
在初始化Web应用程序中的任何过滤器或servlet之前,将通知所有servletContextListener上下文初始化。
@Component
public class MyTest implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("this is contextInitialized");
}
}
以上方法执行顺序
执行顺序是
- Bean的static
- Bean的构造函数
- ServletContextAware
- Bean的PostConstruct
- Bean的InitializingBean
- Bean的initMethod
- ApplicationListener
- ApplicationRunner
测试方法
主方法
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
System.out.println("before main run");
SpringApplication.run(DemoApplication.class, args);
System.out.println("after main run");
}
}
测试方法
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.ServletContextAware;
import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@Configuration
public class TestInitConfig {
@Bean(name = "myUser", initMethod = "initUser")
public Object userBean() {
return new User();
}
public static class User implements ApplicationRunner,
ApplicationListener<ApplicationStartedEvent>,
InitializingBean,
ServletContextAware, ServletContextListener
{
static {
System.out.println("static");
}
User(){
System.out.println("construct");
}
public void initUser() {
System.out.println("initMethod");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean");
}
@PostConstruct
public void userPostConstruct() {
System.out.println("PostConstruct");
}
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner");
}
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("ServletContextAware");
}
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContextListener");
}
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("ApplicationListener");
}
}
}
输出结果
before main run . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.4.13) 2024-03-11 19:43:18.553 INFO 47188 --- [ main] com.knife.example.DemoApplication : Starting DemoApplication using Java 1.8.0_201 on DESKTOP-HLAI48V with PID 47188 (E:\project\Idea_Proj\Demo_Java\Demo_SpringBoot\target\classes started by aaabbb in E:\project\Idea_Proj\Demo_Java\Demo_SpringBoot) 2024-03-11 19:43:18.556 INFO 47188 --- [ main] com.knife.example.DemoApplication : No active profile set, falling back to default profiles: default 2024-03-11 19:43:19.558 INFO 47188 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2024-03-11 19:43:19.566 INFO 47188 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-03-11 19:43:19.566 INFO 47188 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.55] 2024-03-11 19:43:19.640 INFO 47188 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-03-11 19:43:19.640 INFO 47188 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1040 ms static construct ServletContextAware PostConstruct InitializingBean initMethod 2024-03-11 19:43:20.170 INFO 47188 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2024-03-11 19:43:20.403 INFO 47188 --- [ main] com.knife.example.DemoApplication : Started DemoApplication in 2.232 seconds (JVM running for 2.94) ApplicationListener ApplicationRunner after main run

请先 !