美文网首页java日常开发笔记
Spring-boot中的CommandLineRunner的作

Spring-boot中的CommandLineRunner的作

作者: 毁于一蛋 | 来源:发表于2020-01-19 10:39 被阅读0次

    1、场景

        
    Spring-Bean初始化操作的额外操作,比如需在Spring加载完成阶段,添加其他的一些功能,或者需要运行某些特殊的方法脚本。
    比如完成下述代码的示例:

    package com.im;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class ImApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ImApplication.class, args);
            System.out.println("运行方法1");
            System.out.println("运行方法2");
            System.out.println("运行方法3");
            System.out.println("运行方法4");
        }
    }
    
    

    运行结果:


    输入图片说明

        
    这段代码的意思就是,在加载玩springbean后,期望运行,方法1、方法2、方法3、方法4,四个方法而且顺序不变,那么此时的代码这么写肯定是可行的但是可能让人觉着不太美观,因为代码块可能很大,很杂,一个优秀的方法代码逻辑----功能单一,一个方法就围绕一个功能来展开,而不可以一个方法实现多个功能,这样的方法不便于维护,也没有可读性。

    2、使用CommandLineRunner接口来解决上述的问题

    package com.im;
    
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    @SpringBootApplication
    public class ImApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ImApplication.class, args);
        }
    }
    
    @Component
    @Order(1)
    class Function1 implements CommandLineRunner{
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("运行方法1");
        }
    }
    
    @Component
    @Order(2)
    class Function2 implements CommandLineRunner{
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("运行方法2");
        }
    }
    
    @Component
    @Order(3)
    class Function3 implements CommandLineRunner{
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("运行方法3");
        }
    }
    
    @Component
    @Order(4)
    class Function4 implements CommandLineRunner{
    
        @Override
        public void run(String... args) throws Exception {
            System.out.println("运行方法4");
        }
    }
    

    运行结果:

    运行结果

    个人认为,这种写法是比较优秀的写法,方法功能以组件的形式隔离开来,将一个后置方法一组件的形式开发,便于功能隔离,而且代码直观,便于我们维护和扩展。

    3、另外一种形式,@PostConstruct

        
    @PostConstruct源码:

    /*
     * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
     * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     */
    
    package javax.annotation;
    
    import java.lang.annotation.*;
    import static java.lang.annotation.ElementType.*;
    import static java.lang.annotation.RetentionPolicy.*;
    
    /**
     * The PostConstruct annotation is used on a method that needs to be executed
     * after dependency injection is done to perform any initialization. This
     * method MUST be invoked before the class is put into service. This
     * annotation MUST be supported on all classes that support dependency
     * injection. The method annotated with PostConstruct MUST be invoked even
     * if the class does not request any resources to be injected. Only one
     * method can be annotated with this annotation. The method on which the
     * PostConstruct annotation is applied MUST fulfill all of the following
     * criteria:
     * <p>
     * <ul>
     * <li>The method MUST NOT have any parameters except in the case of
     * interceptors in which case it takes an InvocationContext object as
     * defined by the Interceptors specification.</li>
     * <li>The method defined on an interceptor class MUST HAVE one of the
     * following signatures:
     * <p>
     * void &#060;METHOD&#062;(InvocationContext)
     * <p>
     * Object &#060;METHOD&#062;(InvocationContext) throws Exception
     * <p>
     * <i>Note: A PostConstruct interceptor method must not throw application
     * exceptions, but it may be declared to throw checked exceptions including
     * the java.lang.Exception if the same interceptor method interposes on
     * business or timeout methods in addition to lifecycle events. If a
     * PostConstruct interceptor method returns a value, it is ignored by
     * the container.</i>
     * </li>
     * <li>The method defined on a non-interceptor class MUST HAVE the
     * following signature:
     * <p>
     * void &#060;METHOD&#062;()
     * </li>
     * <li>The method on which PostConstruct is applied MAY be public, protected,
     * package private or private.</li>
     * <li>The method MUST NOT be static except for the application client.</li>
     * <li>The method MAY be final.</li>
     * <li>If the method throws an unchecked exception the class MUST NOT be put into
     * service except in the case of EJBs where the EJB can handle exceptions and
     * even recover from them.</li></ul>
     * @since Common Annotations 1.0
     * @see javax.annotation.PreDestroy
     * @see javax.annotation.Resource
     */
    @Documented
    @Retention (RUNTIME)
    @Target(METHOD)
    public @interface PostConstruct {
    }
    
    

    运行结果:

    运行结果

    源码分析:
        
    @Postconstruct注解使用在方法上,一般在依赖注入完成之后才开始执行其标识的方法的初始化。这个方法必须在类注入之前被调用。这个注解所支持的类必须支持依赖注入,这个被标注的方法调用时甚至不需要任何资源的注入(他本身就是在bean注入之前的调用的,所以此时的bean还尚未初始化好),被该注解注释的方法必须满足如下的标准:
    •PostConstruct拦截器方法不能抛出applicationexceptions,但是如果相同的拦截器方法除了生命周期事件之外插入onbusiness或timeout方法,它也可以被声明为抛出包括java.lang.Exception的已检查异常。如果aPostConstruct拦截器方法返回一个值,则容器会忽略它。
    •在非拦截器类上定义的方法必须具有以下签名:
    void <METHOD>()

    •应用PostConstruct的方法可以是公共的,受保护的,包私有的或私有的。
    •除应用程序客户端外,方法不能是静态的。
    •方法可能是最终的。
    •如果方法抛出未经检查的异常,则除了在EJB可以处理异常并且从中恢复异常的EJB的情况下,该类不能被置于intoservice中。
    从以下版本开始:Common Annotations 1.0参见:javax.annotation.PreDestroyjavax.annotation.Resource

    3、两个的区别:

    1、CommandLineRunner的init()实在spring初始化完毕后执行的,即为服务初始化的最后一步操作
    而@postConstruct的操作实在bean依赖注入之前的,相当于spring的容器初始化前的操作。

    对读者:

    初次了解,可能有些不对的地方,希望能够查漏补缺,如有错误的描述理解,望得到指示。

    相关文章

      网友评论

        本文标题:Spring-boot中的CommandLineRunner的作

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