启动就加载(三)initializingbean实现afterPropertiesSet方法
TransactionTemplate,就直接以TransactionTemplate为入口开始学习。
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);
- }
- }
- }
总结:
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");
- }
- }
启动就加载(三)initializingbean实现afterPropertiesSet方法的更多相关文章
- spring启动容器加载成功后执行调用方法
需求: 由于在微服务架构中各服务之间都是通过接口调用来进行交互的,像很多的基础服务,类似字典信息其实并不需每次需要的时候再去请求接口.所以我的想法是每次启动项目的时候,容器初始化完成,就去调用一下基础 ...
- 《Linux内核设计的艺术》学习笔记(一)从开机加电到加载三个汇编源码
实验内核版本:0.11 ◆ 从开机到main函数的三步: ① 启动BIOS,准备实模式下的中断向量表和中断服务程序: ② 从启动盘加载OS程序到内存中,加载OS程序的工作就是利用第一步中的中断服务 ...
- ElasticSearch 启动时加载 Analyzer 源码分析
ElasticSearch 启动时加载 Analyzer 源码分析 本文介绍 ElasticSearch启动时如何创建.加载Analyzer,主要的参考资料是Lucene中关于Analyzer官方文档 ...
- jvm(1)类的加载(三)(线程上下文加载器)
简介: 类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的. Java Applet 需要从远程下载 Java 类文件到浏览器中并执行. 现在类加载器在 ...
- jetty9内嵌到应用,并在启动后加载WebApplicationInitializer,可运行jsp
声明:本文所介绍的两功能都已经测试通过. 第一步先确保你用的是java 8,并依赖需要的相关jar包,以下是用gradle进行依赖的信息: ext { taglibsStandardVersion = ...
- Servlet在启动时加载的tomcat源码(原创)
tomcat 8.0.36 知识点: 通过配置loadOnStartup可以设置Servlet是否在Tomcat启动时加载,以及按值大小进行有序加载,其最小有效值为0,最大有效值为Integer.MA ...
- 启动就加载(一)----注解方式实现的。static项目启动的时候就加载进来(一般用于常用参数)
一,案例 1.1,图片分析 1.2,代码 1.2.1,编写加载系统参数的servlet public class SysInitServlet extends HttpServlet { public ...
- Redis深入学习笔记(一)Redis启动数据加载流程
这两年使用Redis从单节点到主备,从主备到一主多从,再到现在使用集群,碰到很多坑,所以决定深入学习下Redis工作原理并予以记录. 本系列主要记录了Redis工作原理的一些要点,当然配置搭建和使用这 ...
- 基于Spring MVC的web应用随应用启动而加载
写个类实现org.springframework.context.ApplicationContextAware接口即可. 但是如下的程序会在启动时加载两次: @Controller public c ...
- iOS swift 启动页加载广告(图片广告+视频广告)
一般app在启动的时候都会有广告页,广告页用来加载自己的或者第三方的广告,广告的展示形式也多种多样,最近在看swift相关的东西,这里将提供支持加载图片广告和视频广告的解决方案 思路: 我们知道在加载 ...
随机推荐
- bzoj 4836: 二元运算
死活TLE....求助 update 4.3 23:08 求助了tls之后终于过了...分治里次数界写崩了...r-l+1就行... 分治的做法很神奇!本题的限制在于操作类型与权值相对大小有关,而用[ ...
- POJ 2125 Destroying The Graph [最小割 打印方案]
Destroying The Graph Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 8311 Accepted: 2 ...
- spring security 4 filter 顺序及作用
Spring Security 有两个作用:认证和授权 一.Srping security 4 filter 别名及顺序 spring security 4 标准filter别名和顺序,因为经常要用就 ...
- 使用tcp+select实现客户端与客户端的通信
使用多路复用实现客户端与客户端进行通信: 原理:客户端只要一连上服务器,立马给服务器发送用户名,然后在服务端将newsocketfd存放在同一个结构体中,客户端先给服务器发送数据,然后通过服务器转发给 ...
- [Python Study Notes]字典操作
字典操作 a.增加 >>> info["stu1104"] = "abc" >>> info {'stu1102': 'x5 ...
- img alt与title的区别
前端 alt是图片加载不出来时候,对图片的文本替代 title 是鼠标放在图片上时,对图片的进一步说明 seo 搜索引擎对图片意思的理解主要靠 alt
- 微信小程序 sha1 实现密码加密
在utils中的util.js 文件中增加 函数 实现 字符串转换为16进制加密后的字符串 function encodeUTF8(s) { var i, r = [], c, x; for (i = ...
- bzoj 1307/1318 玩具 线段树+记录时间戳
玩具 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 743 Solved: 404[Submit][Status][Discuss] Descrip ...
- 使用Vue和thrift建立前后端交互的demo
初识thrift thrift 是 facebook 于2007年开发的一款跨平台 RPC(Remote Procedure Call) 软件框架, 它可以在多种平台上进行无缝交互,数据传输使用二进制 ...
- C#标识符