spring InitializingBean

spring InitializingBean

大家好,又见面了,我是全栈君。

先说总结:


1:spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用


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


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


4:TransactionTemplate实现InitializingBean接口,主要是判断transactionManager是否已经初始化,如果没有则抛出异常。源码如下:


     public void afterPropertiesSet() {



        if (this.transactionManager == null) {



            throw new IllegalArgumentException(“Property ‘transactionManager’ is required”);


        }


    }



TransactionTemplate的源码如下:


public class TransactionTemplate extends DefaultTransactionDefinition


        implements TransactionOperations, InitializingBean{



        .


        .


        .


        }


TransactionTemplate继承了DefaultTransactionDefinition,实现了TransactionOperations,InitializingBean接口。先研究InitializingBean接口


InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。


测试程序如下:


import org.springframework.beans.factory.InitializingBean;


public class TestInitializingBean implements InitializingBean{





    @Override


    public void afterPropertiesSet() throws Exception {



        System.out.println(“ceshi InitializingBean”);        


    }


    public void testInit(){



        System.out.println(“ceshi init-method”);        


    }


}


配置文件如下:


<?xml version=”1.0″ encoding=”UTF-8″?>


<beans xmlns=”http://www.springframework.org/schema/beans”


    xmlns:context=”http://www.springframework.org/schema/context”


    xmlns:jdbc=”http://www.springframework.org/schema/jdbc” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”


    xmlns:p=”http://www.springframework.org/schema/p” xmlns:aop=”http://www.springframework.org/schema/aop”


    xmlns:tx=”http://www.springframework.org/schema/tx”


    xsi:schemaLocation=”


    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd”>


    <bean id=”testInitializingBean” class=”com.TestInitializingBean” ></bean>


</beans>


Main主程序如下:


public class Main {



    public static void main(String[] args){



        ApplicationContext context = new FileSystemXmlApplicationContext(“/src/main/java/com/beans.xml”);


    }


}


运行Main程序,打印如下结果:


ceshi InitializingBean  


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


问题:实现InitializingBean接口与在配置文件中指定init-method有什么不同?


修改配置文件,加上init-method配置,修改如下:


<?xml version=”1.0″ encoding=”UTF-8″?>


<beans xmlns=”http://www.springframework.org/schema/beans”


    xmlns:context=”http://www.springframework.org/schema/context”


    xmlns:jdbc=”http://www.springframework.org/schema/jdbc” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”


    xmlns:p=”http://www.springframework.org/schema/p” xmlns:aop=”http://www.springframework.org/schema/aop”


    xmlns:tx=”http://www.springframework.org/schema/tx”


    xsi:schemaLocation=”


    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd”>


    <bean id=”testInitializingBean” class=”com.TestInitializingBean” init-method=”testInit”></bean>


</beans>


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


运行Main程序,打印如下结果:


ceshi InitializingBean


ceshi init-method


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




这方式在spring中是怎么实现的?


通过查看spring的加载bean的源码类(AbstractAutowireCapableBeanFactory)可看出其中奥妙


AbstractAutowireCapableBeanFactory类中的invokeInitMethods讲解的非常清楚,源码如下:


protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)


            throws Throwable {



//判断该bean是否实现了实现了InitializingBean接口,如果实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法


        boolean isInitializingBean = (bean instanceof InitializingBean);


        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);


            }


        }


    }



版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/108602.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • Java 事务注解(注解式事务)

    spring中的@Transactional(rollbackFor=Exception.class)事务处理,当你的方法中抛出异常时,它会将事务回滚,数据库中的数据将不会改变,也就是回到进入此方法前的状态。1 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)2 让uncheck

    2022年4月13日
  • redis 缓存技术与memcache的最大差别

    redis 缓存技术与memcache的最大差别

    2021年12月5日
  • hi3531dv200开发板_hi3516dv300参数

    hi3531dv200开发板_hi3516dv300参数前言安装环境,默认你是有Linux系统的,不管是VM虚拟机还是docker还是WSL,也不对系统进行要求。此教程默认环境如下:Ubuntu18.04、Anaconda(Python3.8.5)、Anaconda安装不同版本Python

    2022年9月23日
  • django3.0异步_java定时任务框架选型

    django3.0异步_java定时任务框架选型celery介绍Celery是由Python开发、简单、灵活、可靠的分布式任务队列,是一个处理异步任务的框架,其本质是生产者消费者模型,生产者发送任务到消息队列,消费者负责处理任务。Celery侧重

    2022年7月29日
  • pycharm激活码2022.01.13【2022最新】2022.01.23

    (pycharm激活码2022.01.13)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月31日
  • 微信小程序反编译工具wxappUnpacker使用

    1、下载wxappUnpacker,我这里用的是node版还有其他班自己查https://github.com/qwerty472123/wxappUnpacker2、下载node。js首先需要知道的是小程序在手机里的文件储存位置——那么这个位置具体在哪呢?————具体目录位置:/data/data/com.tencent.mm/MicroMsg/{{一串32位的16进制…

    2022年4月12日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号