• Spring初始化bean:InitializingBean、initmethod


    1、Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口或者通过在XML配置文件中添加init-method的方式,这两种方式可以同时使用。

    2、实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。

    3、如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

    InitializingBean

      InitializingBean是Spring提供的拓展性接口,InitializingBean接口为bean提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。

    作用

    我们直接通过查看源码注释可知 --  InitializingBean源码注释翻译

    示例

    自定义MyInitializingBean实现InitializingBean接口

    1 @Component
    2 public class MyInitializingBean implements InitializingBean {
    3 
    4     @Override
    5     public void afterPropertiesSet() throws Exception {
    6         System.out.println("implements InitializingBean......");
    7     }
    8 
    9 }
    View Code

    运行结果如下:

     这说明在 spring 初始化 bean 的时候,如果 bean 实现了 InitializingBean 接口,会自动调用 afterPropertiesSet 方法。

    问题:如果bean实现了InitializingBean接口,并且同时配置了init-method,会怎么样?

    配置init-method

    我们可以通过XML文件的方式或者更简洁的@Bean注解的方式去配置init-methodf方法。

    一. 通过XML文件方式配置init-method方法

    项目的resource下新建xml文件

    在配置文件中加入 init-method="testInit"。 

    通过配置类加载 xml 配置文件

    /**
     * 通过配置类加载 xml 配置文件
     * @author JustJavaIt
     * @date 2022/9/10 15:20
     */
    @ImportResource(locations = "classpath:bean.xml")
    @Configuration
    public class WebMvcConfig {
    }
    View Code

     然后在MyInitializingBean中添加初始化方法testInit()

    View Code

    注意注释掉@Compoment,否者会报bean已经被定义了

    二.  通过@Bean的方式配置init-method方法

     1 @Component
     2 public class MyInitializingBean implements InitializingBean {
     3 
     4     @Override
     5     public void afterPropertiesSet() throws Exception {
     6         System.out.println("implements InitializingBean......");
     7     }
     8 
     9     public void testInit(){
    10         System.out.println("init-method......");
    11     }
    12 
    13     /**
    14      * 相当于在xml配置文件中加入
    15      * <bean id="myInitializingBean" class="类路径" init-method="testInit"></bean>
    16      * @return
    17      */
    18     @Bean(initMethod = "testInit")
    19     public MyInitializingBean test() {
    20         return new MyInitializingBean();
    21     }
    22 }
    View Code

    最终运行结果

       由结果可看出,在 spring 初始化 bean 的时候,如果该 bean 是实现了 InitializingBean 接口,并且同时在配置文件中指定了 init-method,系统则是先调用 afterPropertiesSet 方法,然后再调用 init-method 中指定的方法

     invokeInitMethods源码分析

      通过查看Spring加载bean的源码类AbstractAutowiredCapableBeanFactory可以看出其中的奥妙,AbstractAutowiredCapableBeanFactory类中的invokeInitMethods说的非常清楚,如下:

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

    InitializingBean扩展

     1 /**
     2  * 构造方法、注解postConstruct,实现InitializingBean方法afterPropertiesSet,bean初始化init方法执行顺序。
     3  * @author JustJavaIt
     4  * @date 2022/9/10 15:030
     5  */
     6 @Component
     7 public class MyInitializingBean implements InitializingBean {
     8     public MyInitializingBean() {
     9         System.out.println("我是MyInitializingBean构造方法执行...");
    10     }
    11 
    12     public void testInit(){
    13         System.out.println("我是init方法执行...");
    14     }
    15 
    16     @Bean(initMethod = "testInit")
    17     public MyInitializingBean test() {
    18         return new MyInitializingBean();
    19     }
    20     
    21     @Override
    22     public void afterPropertiesSet() throws Exception {
    23         System.out.println("我是afterPropertiesSet方法执行...");
    24     }
    25 
    26     @PostConstruct
    27     public void postConstruct() {
    28         System.out.println("我是postConstruct方法执行...");
    29     }
    30 
    31 }
    View Code

     运行结果如下:

     我们可以看出执行顺序优先级:构造方法 > postConstruct >afterPropertiesSet > init方法

  • 相关阅读:
    canvas游戏开发系列(1):基础知识
    HTML5拖拽实例
    Jfinal 源码分析之拦截器的使用
    jfinal ——AOP面向切面编程
    JFinal框架源码分析(二)——JFinal控制器
    企业级Tomcat部署配置
    KICKSTART无人值守安装
    ELK 企业内部日志分析系统
    全球性WannaCry蠕虫勒索病毒感染前后应对措施
    LAMP架构应用实战—Apache服务介绍与安装01
  • 原文地址:https://www.cnblogs.com/liaowenhui/p/16676819.html
Copyright © 2020-2023  润新知