所有分类
  • 所有分类
  • 未分类

SpringBoot–启动时执行的方法

简介

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

法1:实现ApplicationRunner接口(推荐)

继承Application接口后项目启动时会按照执行顺序执行run方法。

定义多个applicationrunner bean时,可以用注解@Order或者实现Ordered接口对其进行排序。

自动执行的方法

@Component
@Order(1)
public class MyTest implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        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) 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"));
    }
}

 配置参数启动:

--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) 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 {

    @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的子类),比如:

  1. ApplicationStartingEvent
  2. ApplicationStartedEvent
  3. ApplicationFailedEvent
  4. ApplicationReadyEvent
  5. ContextRefreshedEvent
  6. ContextStartedEvent
  7. ContextClosedEvent
  8. ContextStoppedEvent
  9. 等等

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

以上方法执行顺序

执行顺序是

  1. Bean的static
  2. Bean的构造函数
  3. ServletContextAware
  4. Bean的PostConstruct
  5. Bean的InitializingBean
  6. Bean的initMethod
  7. ApplicationListener
  8. 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
0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录