服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 详细SpringBoot生命周期接口的使用

详细SpringBoot生命周期接口的使用

2022-12-26 16:37千云 Java教程

本文主要介绍了SpringBoot生命周期接口的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一 背景

最近在做一个项目启动时加载配置到SpringBoot容器中的功能,看到了Spring中有很多在容器初始化时的接口,这些接口或注解包括InitializingBean、@PostConstruct、SmartInitializingSingleton、BeanPostProcess等等,这么多都可以在初始化时使用,但是他们有什么区别呢,下面就来说说他们之间的区别

二 SpringBoot 生命周期接口

  • @PostConstruct

    这个注解在实际的开发中有较多的用到

    ?
    1
    2
    3
    4
    5
    6
    7
    @Component
    public class TestP {
     
        @PostConstruct
        public void test() {
            System.out.println("@PostConstruct");
        }

    这样在容器启动过程中就回执行打印,看起来他像是对象的构造方法,其实他的作用是,当一个对象A中存在@Autowire修饰的依赖B时,正常来说,对象会先执行自己的构造方法,然后再去注入依赖,但是我们现在有一种情况,在对象实例化时,要执行构造方法,但是构造方法中用到依赖B,这个时候用 @PostConstruct就能解决这个问题。

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class TestP implements InitializingBean, SmartInitializingSingleton {
        @Autowired
        Context context;
        ```
        public TestP () {
            System.out.println(context);
        }
        ```
        @PostConstruct
        public void test() {
            System.out.println(context);
            System.out.println("@PostConstruct");
        }

    输出

 null
 com.example.demo1.bean.Context@4f96a58
 @PostConstruct

  • InitializingBean

    他提供bean初始化的回调处理功能,看下这个接口的源码

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
     boolean isInitializingBean = (bean instanceof InitializingBean);
     
    //判断该bean是否实现了实现了InitializingBean接口,如果实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法
     if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
         if (logger.isDebugEnabled()) {
             logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
         }
     
         if (System.getSecurityManager() != null) {
             try {
                 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                     public Object run() throws Exception {
                         //直接调用afterPropertiesSet
                         ((InitializingBean) bean).afterPropertiesSet();
                         return null;
                     }
                 },getAccessControlContext());
             } catch (PrivilegedActionException pae) {
                 throw pae.getException();
             }
         }               
         else {
             //直接调用afterPropertiesSet
             ((InitializingBean) bean).afterPropertiesSet();
         }
     }
     if (mbd != null) {
         String initMethodName = mbd.getInitMethodName();
         //判断是否指定了init-method方法,如果指定了init-method方法,则再调用制定的init-method
         if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                 !mbd.isExternallyManagedInitMethod(initMethodName)) {
             //进一步查看该方法的源码,可以发现init-method方法中指定的方法是通过反射实现
             invokeCustomInitMethod(beanName, bean, mbd);
         }
     }

    可以看到,只要实现了这个接口的bean都会执行里面的afterPropertiesSet方法,那他和 @PostConstruct有什么区别呢,区别是他们的生命周期排序不同,@PostConstruct是对单个Bean实例化时使用,而InitializingBean是在所有spring bean实例化后对bean进行处理,⼤致的步骤是这样的

    实例化bean,这⾥会调⽤构造⽅法

    填充属性,就是依赖注⼊

    初始化bean,

    • 调⽤后置处理器,其中会执⾏@PostConstruct注解⽅法
    • 执⾏bean的⽣命周期中的初始化回调⽅法,也就是InitializingBean接⼝的afterPropertiesSet()⽅法
  • BeanPostProcess

    这个接口主要是对注册的bean中的属性进行初始化时的修改

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Component
    public class BeanPostTest implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("执行1--------------- - " + bean.getClass().getName() + " - " + beanName);
            return null;
        }
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("执行2--------------- - " + bean.getClass().getName() + " - " + beanName);
            return null;
        }
    }

    他和InitializingBean区别一个是执行顺序不同

详细SpringBoot生命周期接口的使用

他有两个方法分别在在InitializingBean执行前执行后执行,第二个区别就是InitializingBean是一个可以进一步调整bean的实例的接口,不过并不是每个类都会来执行这个接口方法,这个接口只针对当前实现类,而BeanPostProcess是针对所有bean的,每一个bean被注册,都会被执行一次这两个方法

  • SmartInitializingSingleton

    这个是在spring 4.1版本才推出的接口,他的执行时时机是在单例预实例化阶段结束时调用,并保证已经创建了所有常规单例bean,所以他的执行顺序是比较靠后的,考虑到一些bean的注册及修改使用SmartInitializingSingleton是比较稳妥的一种方式

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ```
    @Component
    public class GetuiAccountConfigInit implements SmartInitializingSingleton  {
     
     
        @Override
        public void afterSingletonsInstantiated() {
     
        }
    }
    ```
  • Commandlinerunner 这个接口是springBoot的接口,他是在所有bean都加载后才会执行的,如果实现这个接口,可以很好的在启动时初始化资源,因为所有的bean都可以使用了

    ?
    1
    2
    3
    4
    5
    6
    7
    @Component
    public class Runner implements CommandLineRunner {
        @Override
        public void run(String... args) throws Exception {
            System.out.println("执行初始化");
        }
    }

    如果我们要执行的程序有顺序要求,还可以使用@Order注解

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Component
    @Order(1)
    public class OrderRunner1 implements CommandLineRunner {
        @Override
        public void run(String... args) throws Exception {
            System.out.println("The OrderRunner1 start to initialize ...");
        }
    }
    @Component
    @Order(2)
    public class OrderRunner1 implements CommandLineRunner {
        @Override
        public void run(String... args) throws Exception {
            System.out.println("The OrderRunner2 start to initialize ...");
        }
    }

三 后记

Spring由于设计上比较灵活所以留了很多接口,让开发人员进行拓展,这本身是一个很好的学习借鉴的经验,现在大部分的开发使用的都是spring的框架,这就要求我们做一些设计时要了解框架的特性,才能进行更好的设计,上面的几个接口是相对来说比较常用的接口,里面的技术细节也值得推敲,希望对大家有所帮助。

到此这篇关于详细SpringBoot生命周期接口的使用的文章就介绍到这了,更多相关SpringBoot生命周期接口内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://juejin.cn/post/7101631306261331999

延伸 · 阅读

精彩推荐
  • Java教程Java 面试题和答案 - (下)

    Java 面试题和答案 - (下)

    本文主要介绍Java 面试题,这里整理了Java面试题关于JDBC,线程异常处理,Servlet,JSP的知识的整理,帮助大家理解知识点,便于面试,有兴趣的小伙伴可以参...

    ImportNew4052020-06-10
  • Java教程Spring MVC实现的登录拦截器代码分享

    Spring MVC实现的登录拦截器代码分享

    这篇文章主要介绍了Spring MVC实现的登录拦截器代码分享,涉及拦截器的简单介绍,拦截器和过滤器的区以及拦截器实现代码等相关内容,这里分享给大家,...

    黄小鱼ZZZ9332021-01-22
  • Java教程java中RabbitMQ高级应用

    java中RabbitMQ高级应用

    本文主要介绍了java中RabbitMQ高级应用,中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一...

    beordie10362022-11-30
  • Java教程使用@PathVariable接收两个参数

    使用@PathVariable接收两个参数

    这篇文章主要介绍了使用@PathVariable接收两个参数的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    快乐的小三菊6482021-11-30
  • Java教程Spring的注解配置与XML配置之间的比较

    Spring的注解配置与XML配置之间的比较

    在很多情况下,注释配置比 XML 配置更受欢迎,注释配置有进一步流行的趋势。Spring 2.5 的一大增强就是引入了很多注释类,现在您已经可以使用注释配置完...

    java之家4312019-10-14
  • Java教程不重复造轮子都是骗小孩的,教你手撸 SpringBoot 脚手架!

    不重复造轮子都是骗小孩的,教你手撸 SpringBoot 脚手架!

    虽然市面上已经有了大量成熟稳定用于支撑系统建设的轮子,也就是服务、框架、组件、工具等,但对于一些较大型的公司来说,这些轮子可能并不一定能...

    bugstack虫洞栈3802021-03-16
  • Java教程Java内存划分:运行时数据区域

    Java内存划分:运行时数据区域

    听说Java运行时环境的内存划分是挺进BAT的必经之路,这篇文章主要给大家介绍了关于Java运行时数据区域(内存划分)的相关资料,需要的朋友可以参考下...

    一颗苹果.10452021-10-06
  • Java教程java实现随机验证码图片生成

    java实现随机验证码图片生成

    这篇文章主要为大家详细介绍了java实现随机验证码图片生成,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    夕阳西下,断肠人在天涯7942022-03-13