TransactionTemplate,就直接以TransactionTemplate为入口开始学习。

TransactionTemplate的源码如下:

  1. public class TransactionTemplate extends DefaultTransactionDefinition
  2. implements TransactionOperations, InitializingBean{
  3. .
  4. .
  5. .
  6. }

TransactionTemplate继承了DefaultTransactionDefinition,实现了TransactionOperations,InitializingBean接口。先研究InitializingBean接口
InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。
测试程序如下:

  1. import org.springframework.beans.factory.InitializingBean;
  2. public class TestInitializingBean implements InitializingBean{
  3. @Override
  4. public void afterPropertiesSet() throws Exception {
  5. System.out.println("ceshi InitializingBean");
  6. }
  7. public void testInit(){
  8. System.out.println("ceshi init-method");
  9. }
  10. }

配置文件如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
  6. xmlns:tx="http://www.springframework.org/schema/tx"
  7. xsi:schemaLocation="
  8. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  9. <bean id="testInitializingBean" class="com.TestInitializingBean" ></bean>
  10. </beans>

Main主程序如下:

  1. public class Main {
  2. public static void main(String[] args){
  3. ApplicationContext context = new FileSystemXmlApplicationContext("/src/main/java/com/beans.xml");
  4. }
  5. }

运行Main程序,打印如下结果:
ceshi InitializingBean  
这说明在spring初始化bean的时候,如果bean实现了InitializingBean接口,会自动调用afterPropertiesSet方法。
问题:实现InitializingBean接口与在配置文件中指定init-method有什么不同?
修改配置文件,加上init-method配置,修改如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
  6. xmlns:tx="http://www.springframework.org/schema/tx"
  7. xsi:schemaLocation="
  8. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  9. <bean id="testInitializingBean" class="com.TestInitializingBean" init-method="testInit"></bean>
  10. </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讲解的非常清楚,源码如下:

  1. protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
  2. throws Throwable {
  3. //判断该bean是否实现了实现了InitializingBean接口,如果实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法
  4. boolean isInitializingBean = (bean instanceof InitializingBean);
  5. if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
  6. if (logger.isDebugEnabled()) {
  7. logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
  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. }

总结:
1:spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用
2:实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖
3:如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。
4:TransactionTemplate实现InitializingBean接口,主要是判断transactionManager是否已经初始化,如果没有则抛出异常。源码如下:

    1. public void afterPropertiesSet() {
    2. if (this.transactionManager == null) {
    3. throw new IllegalArgumentException("Property 'transactionManager' is required");
    4. }
    5. }

启动就加载(三)initializingbean实现afterPropertiesSet方法的更多相关文章

  1. spring启动容器加载成功后执行调用方法

    需求: 由于在微服务架构中各服务之间都是通过接口调用来进行交互的,像很多的基础服务,类似字典信息其实并不需每次需要的时候再去请求接口.所以我的想法是每次启动项目的时候,容器初始化完成,就去调用一下基础 ...

  2. 《Linux内核设计的艺术》学习笔记(一)从开机加电到加载三个汇编源码

      实验内核版本:0.11 ◆ 从开机到main函数的三步: ① 启动BIOS,准备实模式下的中断向量表和中断服务程序: ② 从启动盘加载OS程序到内存中,加载OS程序的工作就是利用第一步中的中断服务 ...

  3. ElasticSearch 启动时加载 Analyzer 源码分析

    ElasticSearch 启动时加载 Analyzer 源码分析 本文介绍 ElasticSearch启动时如何创建.加载Analyzer,主要的参考资料是Lucene中关于Analyzer官方文档 ...

  4. jvm(1)类的加载(三)(线程上下文加载器)

    简介: 类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的. Java Applet 需要从远程下载 Java 类文件到浏览器中并执行. 现在类加载器在 ...

  5. jetty9内嵌到应用,并在启动后加载WebApplicationInitializer,可运行jsp

    声明:本文所介绍的两功能都已经测试通过. 第一步先确保你用的是java 8,并依赖需要的相关jar包,以下是用gradle进行依赖的信息: ext { taglibsStandardVersion = ...

  6. Servlet在启动时加载的tomcat源码(原创)

    tomcat 8.0.36 知识点: 通过配置loadOnStartup可以设置Servlet是否在Tomcat启动时加载,以及按值大小进行有序加载,其最小有效值为0,最大有效值为Integer.MA ...

  7. 启动就加载(一)----注解方式实现的。static项目启动的时候就加载进来(一般用于常用参数)

    一,案例 1.1,图片分析 1.2,代码 1.2.1,编写加载系统参数的servlet public class SysInitServlet extends HttpServlet { public ...

  8. Redis深入学习笔记(一)Redis启动数据加载流程

    这两年使用Redis从单节点到主备,从主备到一主多从,再到现在使用集群,碰到很多坑,所以决定深入学习下Redis工作原理并予以记录. 本系列主要记录了Redis工作原理的一些要点,当然配置搭建和使用这 ...

  9. 基于Spring MVC的web应用随应用启动而加载

    写个类实现org.springframework.context.ApplicationContextAware接口即可. 但是如下的程序会在启动时加载两次: @Controller public c ...

  10. iOS swift 启动页加载广告(图片广告+视频广告)

    一般app在启动的时候都会有广告页,广告页用来加载自己的或者第三方的广告,广告的展示形式也多种多样,最近在看swift相关的东西,这里将提供支持加载图片广告和视频广告的解决方案 思路: 我们知道在加载 ...

随机推荐

  1. CF798E. Mike and code of a permutation [拓扑排序 线段树]

    CF798E. Mike and code of a permutation 题意: 排列p,编码了一个序列a.对于每个i,找到第一个\(p_j > p_i\)并且未被标记的j,标记这个j并\( ...

  2. Codeforces 250 E. The Child and Binary Tree [多项式开根 生成函数]

    CF Round250 E. The Child and Binary Tree 题意:n种权值集合C, 求点权值和为1...m的二叉树的个数, 形态不同的二叉树不同. 也就是说:不带标号,孩子有序 ...

  3. BZOJ 3790: 神奇项链 [Manacher 贪心]

    3790: 神奇项链 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 405  Solved: 200[Submit][Status][Discuss] ...

  4. Eclipse多平台编译(armeabi, armeabi-v7a, x86, mips)

    Jni目录下新增Application.mk,加入 APP_ABI := armeabi armeabi-v7a x86 mips 上面的平台可加可减,全编的话可以写为 APP_ABI := all ...

  5. SpringMVC之Http标准的头部信息

  6. 测试人员如何使用Git部署测试环境

    Git是分布式的版本控制系统. 作为一名Git的小白使用者,一开始接触很懵逼,因为总担心自己一不小心误操作影响代码仓库的代码,网络上关于Git的使用多从开发的角度,很少有人从测试的角度来介绍Git的使 ...

  7. 痞子衡随笔:常用的数据传输差错检测技术(1)- 奇偶校验(Parity Check)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式数据传输里的差错检测技术-奇偶校验. 在嵌入式应用里,除了最核心的数据处理外,我们还会经常和数据传输打交道.数据传输需要硬件传输接口 ...

  8. IOS中DES与MD5加密方案

      0 2 项目中用的的加密算法,因为要和安卓版的适配,中间遇到许多麻烦. MD5算法和DES算法是常见的两种加密算法. MD5:MD5是一种不可逆的加密算法,按我的理解,所谓不可逆,就是不能解密,那 ...

  9. JAVA死锁

    死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不能正常运行. 简单的说就是:线程死锁时,第一个线程等待第二个线程释放资源,而同时第 ...

  10. 获取对象属性类型、属性名称、属性值的研究:反射和JEXL解析引擎

    同步发布:http://www.yuanrengu.com/index.php/20170511.html 先简单介绍下反射的概念:java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所 ...