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

SpringBoot-启动时执行的方法

简介

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

  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

请先

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

社交账号快速登录