简介
在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
请先
!