简介

        在SpringBoot中我们有时候需要让项目在启动时提前加载相应的数据或者执行某个方法。本文介绍如何在启动时执行,方案很全,且都有实例。

法1:静态方法/@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'

法2:实现InitializingBean接口

@Component
public class MyTest implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
}

法3:提供initMethod

@Configuration
public class MyTest {

@Bean(name = "myUser", initMethod = "initUser")
Object myUser() {
return new User();
}

public static class User {
public void initUser() {
System.out.println("initMethod");
}
}
}

法4:实现ApplicationRunner接口

        继承Application接口后项目启动时会按照执行顺序执行run方法。可以定义多个applicationrunner bean。在同一应用程序上下文中,可以使用有序接口或@order注释对其进行排序。

自动执行的方法

@Component
@Order(1)
public class MyTest implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("this is ApplicationRunner:run");
}
}

        我们也可以设置Order来设定执行的顺序,在上面两个代码中也有,分别是注解​@Order(value = 1)​和实现接口​implements Ordered​的方式,个人喜欢注解,简单明了。实现接口​implements Ordered​的方式如下:

@Component
public class MyTest implements ApplicationRunner, Ordered {
@Override
public int getOrder() {
return 1;
}

@Override
public void run(ApplicationArguments args) throws Exception {
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) throws Exception {
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"));
}
}

 配置参数启动:

SpringBoot--启动时执行--方案大全/方法/实例_Spring启动时执行

运行结果:

===MyApplicationRunner===[--foo=bar, --developer.name=xiao.qiang]
===getOptionNames========[foo, developer.name]
===getOptionValues=======[bar]
==getOptionValues========[xiao.qiang]

法5:实现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) throws Exception {
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 {
private static final Logger logger = LoggerFactory.getLogger(CommandLineRunnerBean.class);

@Override
public void run(String... args) {
String strArgs = Arrays.stream(args).collect(Collectors.joining("|"));
logger.info("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

输出结果

2017-03-19 13:38:38.909  INFO 1036 --- [           main] c.c.bean.CommandLineRunnerBean           : Application started with arguments:data1|data2|data3

法6:在启动类的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

法7:@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秒打印一次。

法8:实现ApplicationListener接口

onApplicationEvent属于应用层的时间。注意,如果下边这个MyTest类中注入了其他类,这个覆写的方法会执行两次,此时spring容器会被刷新。

@Component
public class MyTest implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("onApplicationEvent");
}
}

法9:实现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");
}
}

法10:实现ServletContextListener接口

在初始化Web应用程序中的任何过滤器或servlet之前,将通知所有servletContextListener上下文初始化。

@Component
public class MyTest implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("this is contextInitialized");
}
}

以上方法执行顺序

主函数

@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");
}

}

测试函数

package com.example.config;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
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")
Object userBean() {
return new User();
}

public static class User implements InitializingBean, ApplicationRunner,
ApplicationListener<ContextRefreshedEvent>,
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 onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("ApplicationListener");
}

@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("ServletContextAware");
}

@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContextListener");
}
}
}

输出结果

"D:\Program Files\Java\jdk1.8.0_201\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:55391,suspend=y,server=n -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:C:\Users\Liu\AppData\Local\Temp\captureAgent7jars\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_201\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_201\jre\lib\rt.jar;E:\work\Idea_proj\demo_JAVA\demo_SpringBoot\target\classes;E:\work\maven\repository\org\springframework\boot\spring-boot-starter-web\2.3.0.RELEASE\spring-boot-starter-web-2.3.0.RELEASE.jar;E:\work\maven\repository\org\springframework\boot\spring-boot-starter\2.3.0.RELEASE\spring-boot-starter-2.3.0.RELEASE.jar;E:\work\maven\repository\org\springframework\boot\spring-boot\2.3.0.RELEASE\spring-boot-2.3.0.RELEASE.jar;E:\work\maven\repository\org\springframework\boot\spring-boot-autoconfigure\2.3.0.RELEASE\spring-boot-autoconfigure-2.3.0.RELEASE.jar;E:\work\maven\repository\org\springframework\boot\spring-boot-starter-logging\2.3.0.RELEASE\spring-boot-starter-logging-2.3.0.RELEASE.jar;E:\work\maven\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;E:\work\maven\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;E:\work\maven\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.2\log4j-to-slf4j-2.13.2.jar;E:\work\maven\repository\org\apache\logging\log4j\log4j-api\2.13.2\log4j-api-2.13.2.jar;E:\work\maven\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;E:\work\maven\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;E:\work\maven\repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;E:\work\maven\repository\org\springframework\boot\spring-boot-starter-json\2.3.0.RELEASE\spring-boot-starter-json-2.3.0.RELEASE.jar;E:\work\maven\repository\com\fasterxml\jackson\core\jackson-databind\2.11.0\jackson-databind-2.11.0.jar;E:\work\maven\repository\com\fasterxml\jackson\core\jackson-core\2.11.0\jackson-core-2.11.0.jar;E:\work\maven\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.0\jackson-datatype-jdk8-2.11.0.jar;E:\work\maven\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.0\jackson-datatype-jsr310-2.11.0.jar;E:\work\maven\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.0\jackson-module-parameter-names-2.11.0.jar;E:\work\maven\repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.0.RELEASE\spring-boot-starter-tomcat-2.3.0.RELEASE.jar;E:\work\maven\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.35\tomcat-embed-core-9.0.35.jar;E:\work\maven\repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;E:\work\maven\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.35\tomcat-embed-websocket-9.0.35.jar;E:\work\maven\repository\org\springframework\spring-web\5.2.6.RELEASE\spring-web-5.2.6.RELEASE.jar;E:\work\maven\repository\org\springframework\spring-beans\5.2.6.RELEASE\spring-beans-5.2.6.RELEASE.jar;E:\work\maven\repository\org\springframework\spring-webmvc\5.2.6.RELEASE\spring-webmvc-5.2.6.RELEASE.jar;E:\work\maven\repository\org\springframework\spring-aop\5.2.6.RELEASE\spring-aop-5.2.6.RELEASE.jar;E:\work\maven\repository\org\springframework\spring-context\5.2.6.RELEASE\spring-context-5.2.6.RELEASE.jar;E:\work\maven\repository\org\springframework\spring-expression\5.2.6.RELEASE\spring-expression-5.2.6.RELEASE.jar;E:\work\maven\repository\net\bytebuddy\byte-buddy\1.10.10\byte-buddy-1.10.10.jar;E:\work\maven\repository\org\springframework\spring-core\5.2.6.RELEASE\spring-core-5.2.6.RELEASE.jar;E:\work\maven\repository\org\springframework\spring-jcl\5.2.6.RELEASE\spring-jcl-5.2.6.RELEASE.jar;E:\work\maven\repository\com\alibaba\fastjson\1.2.71\fastjson-1.2.71.jar;E:\work\maven\repository\io\springfox\springfox-swagger2\2.7.0\springfox-swagger2-2.7.0.jar;E:\work\maven\repository\io\swagger\swagger-annotations\1.5.13\swagger-annotations-1.5.13.jar;E:\work\maven\repository\io\swagger\swagger-models\1.5.13\swagger-models-1.5.13.jar;E:\work\maven\repository\com\fasterxml\jackson\core\jackson-annotations\2.11.0\jackson-annotations-2.11.0.jar;E:\work\maven\repository\io\springfox\springfox-spi\2.7.0\springfox-spi-2.7.0.jar;E:\work\maven\repository\io\springfox\springfox-core\2.7.0\springfox-core-2.7.0.jar;E:\work\maven\repository\io\springfox\springfox-schema\2.7.0\springfox-schema-2.7.0.jar;E:\work\maven\repository\io\springfox\springfox-swagger-common\2.7.0\springfox-swagger-common-2.7.0.jar;E:\work\maven\repository\io\springfox\springfox-spring-web\2.7.0\springfox-spring-web-2.7.0.jar;E:\work\maven\repository\org\reflections\reflections\0.9.11\reflections-0.9.11.jar;E:\work\maven\repository\org\javassist\javassist\3.21.0-GA\javassist-3.21.0-GA.jar;E:\work\maven\repository\com\google\guava\guava\18.0\guava-18.0.jar;E:\work\maven\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;E:\work\maven\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;E:\work\maven\repository\org\springframework\plugin\spring-plugin-core\1.2.0.RELEASE\spring-plugin-core-1.2.0.RELEASE.jar;E:\work\maven\repository\org\springframework\plugin\spring-plugin-metadata\1.2.0.RELEASE\spring-plugin-metadata-1.2.0.RELEASE.jar;E:\work\maven\repository\org\mapstruct\mapstruct\1.1.0.Final\mapstruct-1.1.0.Final.jar;E:\work\maven\repository\io\springfox\springfox-swagger-ui\2.7.0\springfox-swagger-ui-2.7.0.jar;E:\work\maven\repository\org\projectlombok\lombok\1.16.20\lombok-1.16.20.jar;D:\Program Files\JetBrains\IntelliJ IDEA 2020.2\lib\idea_rt.jar" com.example.DemoApplication
Connected to the target VM, address: '127.0.0.1:55391', transport: 'socket'
before main run

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.0.RELEASE)

2021-02-21 12:00:59.269 INFO 11692 --- [ main] com.example.DemoApplication : Starting DemoApplication on DESKTOP-QI6B9ME with PID 11692 (E:\work\Idea_proj\demo_JAVA\demo_SpringBoot\target\classes started by Liu in E:\work\Idea_proj\demo_JAVA\demo_SpringBoot)
2021-02-21 12:00:59.272 INFO 11692 --- [ main] com.example.DemoApplication : No active profile set, falling back to default profiles: default
2021-02-21 12:00:59.980 INFO 11692 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-02-21 12:00:59.988 INFO 11692 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-02-21 12:00:59.988 INFO 11692 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.35]
2021-02-21 12:01:00.071 INFO 11692 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-02-21 12:01:00.071 INFO 11692 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 763 ms
static
construct
ServletContextAware
PostConstruct
InitializingBean
initMethod
2021-02-21 12:01:00.213 INFO 11692 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2021-02-21 12:01:00.339 INFO 11692 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
ApplicationListener
2021-02-21 12:01:00.347 INFO 11692 --- [ main] com.example.DemoApplication : Started DemoApplication in 1.403 seconds (JVM running for 2.405)
ApplicationRunner
after main run