美文网首页IT必备技能
实践!在Spring Boot启动时添加方法运行,一文全懂

实践!在Spring Boot启动时添加方法运行,一文全懂

作者: 今天你敲代码了吗 | 来源:发表于2021-02-02 20:37 被阅读0次

    springboot最佳实践:在Spring Boot启动时添加方法运行

    在开发Spring Boot应用程序时,有时我们需要在启动时运行方法或一段代码。这段代码可以是任何内容,从记录某些信息到设置数据库,cron作业等。我们不能仅将此代码放入构造函数中,因为所需的变量或服务可能尚未初始化。这可能导致空指针或其他一些异常。

    为什么我们需要在Spring Boot启动时运行代码?

    由于多种原因,我们需要在应用程序启动时运行方法,

    • 记录重要的事情或说应用程序已启动的消息
    • 处理数据库或文件,建立索引,创建缓存等。
    • 启动后台进程,例如发送通知,从某些队列中获取数据等。

    在Spring Boot中启动后运行方法的不同方法

    每种方式都有其自身的优势。让我们详细看一下以确定应该使用哪个,

    1. 使用CommandLineRunner界面
    2. 带有ApplicationRunner界面
    3. Spring Boot应用程序事件
    4. @Postconstruct方法的注释
    5. InitializingBean接口
    6. @bean批注的Init属性

    1.使用CommandLineRunner界面

    CommandLineRunner是一个弹簧启动功能界面,用于在应用程序启动时运行代码。它位于软件包org.springframework.boot下。

    在上下文初始化之后的启动过程中,spring boot使用提供给应用程序的命令行参数调用其run()方法。

    要通知spring boot我们的commandlineRunner接口,我们可以实现它并在类上方添加@Component批注,或者使用@bean创建其bean。

    实现CommandLineRunner接口的示例

    
    @Component
    public class CommandLineRunnerImpl implements CommandLineRunner {
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("In CommandLineRunnerImpl ");
    
            for (String arg : args) {
                System.out.println(arg);
            }
        }
    }
    

    创建CommandLineRunner接口Bean的示例

    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class);
        }
    
        @Bean
        public CommandLineRunner CommandLineRunnerBean() {
            return (args) -> {
                System.out.println("In CommandLineRunnerImpl ");
    
                for (String arg : args) {
                    System.out.println(arg);
                }
            };
        }
    }
    

    我们可以使用命令行或IDE运行应用程序。让我们举一个例子,当我们使用参数“ –status = running”运行应用程序时

    mvn spring-boot:run -Dspring-boot.run.arguments="--status=running"
    

    要么

    mvn package 
    java -jar target/<FILENAME.JAR HERE> --status=running
    

    这将产生以下日志输出:

    In CommandLineRunnerImpl
    status=running
    

    如我们所见,该参数未解析,而是解释为单个值“ status = running”。

    要访问已解析格式的命令行参数,我们需要使用ApplicationRunner接口。我们待会儿再看。

    Spring Boot将CommandLineRunner接口添加到启动过程中。因此,在commandliner Runner中引发异常将迫使Spring启动中止启动。

    我们可以在一个应用程序中创建多个CommandLineRunner。使用Ordered接口或@Order批注,我们可以配置它们的运行顺序。较低的值表示较高的优先级。默认情况下,所有组件均以最低优先级创建。这就是为什么没有订单配置的组件将被最后调用的原因。

    我们可以使用订单注释,如下所示

    @Component
    @Order(1)
    public class CommandLineRunnerImpl implements CommandLineRunner {
        ........
    }
    

    2.具有ApplicationRunner界面

    如前所述,要访问已解析的参数,我们需要使用ApplicationRunner接口。ApplicationRunner接口为运行方法提供ApplicationArguments而不是原始字符串数组。

    ApplicationArguments是一个接口,可从org.springframework.boot软件包下的boot 1.3 srping中获得。

    它提供了以下几种访问参数的方法

    image.png

    方法getOptionValues返回值列表,因为参数值可以是数组,因为我们可以在命令行中多次使用同一键。 例如–name =“ stacktrace” —端口= 8080 –name =“ guru”

    作为接口实现的应用程序运行器示例

    让我们使用“ status = running –mood = happy 10 –20”参数运行以下程序,并了解输出

    @Component
    public class ApplicationRunnerImpl implements ApplicationRunner {
    
       @Override
       public void run(ApplicationArguments args) throws Exception {
    
          System.out.println("ApplicationRunnerImpl Called");
    
    //print all arguemnts: arg: status=running, arg: --mood=happy, 10, --20
          for (String arg : args.getSourceArgs()) {
             System.out.println("arg: "+arg);
          }
          System.out.println("NonOptionArgs: "+args.getNonOptionArgs()); //[status=running,10]
          System.out.println("OptionNames: "+args.getOptionNames());  //[mood, 20]
    
         System.out.println("Printing key and value in loop:");
          for (String key : args.getOptionNames()) {
             System.out.println("key: "+key);     //key: mood  //key: 20
             System.out.println("val: "+args.getOptionValues(key)); //val:[happy] //val:[]
          }
       }
    }
    

    输出:

    ApplicationRunnerImpl Called
    arg: status=running
    arg: --mood=happ
    arg: 10
    arg: --20
    NonOptionArgs: [status=running , 10]
    OptionNames: [mood, 20]
    Printing key and value in loop:
    key: mood
    val: [happy]
    key: 20
    val: []
    

    CommandLineRunner和ApplicationRunner具有类似的功能,例如

    • run()方法中的异常将中止应用程序启动
    • 可以使用Ordered接口或@Order批注来订购多个ApplicationRunner

    需要注意的最重要一点是,命令在CommandLineRunners和ApplicationRunners之间共享。这意味着可以在commandlinerRunner和applicationRunner之间混合执行顺序。

    3. Spring Boot中的应用程序事件

    Spring框架在不同情况下触发不同事件。它还会在启动过程中触发许多事件。我们可以使用这些事件来执行代码,例如,在Spring Boot应用程序启动后,可以使用ApplicationReadyEvent执行代码。

    如果我们不需要命令行参数,这是在应用程序启动后执行代码的最佳方法。

    @Component
    public class RunAfterStartup{
    
    @EventListener(ApplicationReadyEvent.class)
    public void runAfterStartup() {
        System.out.println("Yaaah, I am running........");
    }
    

    输出:

    Yaaah, I am running........
    

    春季靴子中最重要的事件是

    • ApplicationContextInitializedEvent :在准备ApplicationContext并调用ApplicationContextInitializers之后但在加载bean定义之前触发
    • ApplicationPreparedEvent :在加载bean定义后触发
    • ApplicationStartedEvent :在刷新上下文之后但在调用命令行和应用程序运行程序之前触发
    • ApplicationReadyEvent :在调用任何应用程序和命令行运行程序之后触发
    • ApplicationFailedEvent :如果启动时发生异常则触发

    可以创建多个ApplicationListeners。可以使用@Order批注或Ordered接口对其进行订购。

    该顺序与其他相同类型的ApplicationListener共享,但不与ApplicationRunners或CommandLineRunners共享。

    4.方法上的@Postconstruct注解

    可以使用@PostConstruct批注标记方法。每当使用此注释标记方法时,将在依赖项注入后立即调用该方法。

    @PostConstruct方法链接到特定的类,因此它仅应用于特定于类的代码。每个类只有一个带有postConstruct批注的方法。

    @Component
    public class PostContructImpl {
    
        public PostContructImpl() {
            System.out.println("PostContructImpl Constructor called");
        }
    
        @PostConstruct
        public void runAfterObjectCreated() {
            System.out.println("PostContruct method called");
        }
    
    }
    
    

    输出:

    PostContructImpl Constructor called
    postContruct method called
    

    需要注意的是,如果class标记为lazy,则意味着在请求时创建了class。之后,将执行标有@postConstruct批注的方法。

    标有postConstruct批注的方法可以具有任何名称,但是不能具有任何参数。它必须是无效的,并且不能是静态的。

    请注意,@postConstruct批注是Java EE模块的一部分,在Java 9中被标记为已弃用,在Java 11中已被删除。我们仍然可以通过将java.se.ee添加到应用程序中来使用它。

    5. InitializingBean接口

    InitializingBean解决方案的工作原理与postConstruct批注完全相似。不必使用注释,我们必须实现InitializingBean接口。然后,我们需要重写afterPropertiesSet()方法。

    InitializingBean是org.springframework.beans.factory包的一部分。

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

    您必须考虑如果同时使用@PostConstruct批注和InitializingBean会发生什么。那么在这种情况下,@PostConstruct方法将在InitializingBean的afterPropertiesSet()方法之前调用。

    6. @bean批注的init属性

    我们可以在@Bean批注中使用initMethod属性提供一种方法。bean初始化后将调用此方法。

    initMethod中提供的方法必须为空,并且不能包含任何参数。此方法甚至可以是私有的。

    public class BeanInitMethodImpl {
    
        public void runAfterObjectCreated() {
            System.out.println("yooooooooo......... someone called me");
        }
    }
    
    @SpringBootApplication
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
        @Bean(initMethod="runAfterObjectCreated")
        public BeanInitMethodImpl getFunnyBean() {
            return new BeanInitMethodImpl();
        }
     }
    

    输出:

    yooooooooo......... someone called me
    

    如果您具有同一类的InitializingBean实现和@Bean批注的initMethod属性,则将initMethod之前调用InitializingBean的afterPropertiesSet方法。

    结合不同的方法:

    最后,有时我们可能需要组合多个选项。然后,它们将按照以下顺序执行:

    • 建设者
    • 后构造方法
    • afterPropertiesSet方法
    • Bean初始化方法
    • ApplicationStartedEvent
    • ApplicationRunner或CommandLineRunner取决于顺序
    • ApplicationReadyEvent

    快速阅读

    • 春季启动应用程序启动后,有多种方法可以运行代码
    • 我们可以使用CommandLineRunner或ApplicationRunner接口
    • 使用ApplicationRunner接口访问已解析的参数,而不是原始字符串数组
    • Spring Boot事件在应用程序启动时执行代码
    • 标有@PostConstruct批注的方法在对象初始化后执行
    • 对象初始化之后调用InitializingBean接口的afterPropertiesSet()方法
    • @Bean批注具有属性“ initMethod”以提供将在bean初始化后调用的方法

    相关话题

    • Spring Boot项目设置指南

    作者:小隐乐乐
    链接:https://juejin.cn/post/6911568256289800206
    来源:掘金

    相关文章

      网友评论

        本文标题:实践!在Spring Boot启动时添加方法运行,一文全懂

        本文链接:https://www.haomeiwen.com/subject/wycutltx.html