美文网首页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