Spring源码解读笔记

第一部分 Spring概述

1. Spring简介

Spring 是分层的轻量级开源框架,以IoC和AOP为内核,提供展现层SpringMVC和业务层事务管理等众多企业级应用技术,可以整合众多著名第三方框架和类库,成为使用最多的Java EE企业应用开源框架。

2. Spring优势

  • 解耦合,简化开发:提供IoC容器,将对象间的依赖关系交由Spring控制,避免硬编码造成程序耦合,用户可以更专注于上层的应用。
  • AOP编程支持:提供AOP功能,方便进行面向切面编程。
  • 声明式事务支持:可以通过声明式事务灵活进行事务管理,提高开发效率和质量。
  • 方便集成各种开源框架:提供了对各种优秀框架(Struts、Hibernate、Quartz等)的支持。
  • 降低JavaEE API的使用难度:对JavaEE API(JDBC、JavaMail、远程调用等)进行封装,使用难度降低。

3. Spring的核心结构

Spring是一个分层清晰并且依赖关系、职责定位明确的轻量级框架,主要包括几大模块:数据处理模块、Web模块、AOP/Aspects模块、Core Container模块和Test模块。

Spring源码解读笔记_第1张图片

  • Spring核心容器(Core container):Spring框架最核心的部分,管理着Spring应用中bean的创建、配置和管理,提供DI功能。
  • 面向切面编程(AOP/Aspects):Spring对面向切面编程提供支持,可以帮助应用对象解耦合。
  • 数据访问与集成(Data Access):Spring的JDBC和DAO模块封装了大量模版代码,可以使得数据库代码变得简洁,让开发者更专注于业务,还可避免数据库资源释放失败而引起的问题。AOP为数据访问提供了事务管理服务,同时还对ORM进行集成。
  • Web模块:提供了SpringMVC框架给Web应用,还提供了多种构建和其他应用交互的远程调用方案。
  • Test模块:集成了Junit,使得开发者能够更方便的进行测试。

第二部分 核心思想

注意:IoC和AOP并不是Spring提出,在Spring之前就已经存在,只不过更偏向于理论化,Spring只是在技术层次把这两个思想做了非常好的实现。

1. IoC

1.1 什么是IoC?

IoC全称IoC Inversion of Control(控制反转),它是一个技术思想,不是一个技术实现。

描述的事情:Java开发领域对象的创建、管理的问题

传统开发方式:比如类A依赖于类B,通常会在类A中new一个B的对象

IoC思想下开发方式:不用自己new对象,而是由IoC容器去实例化对象并管理它,开发者需要哪个对象,直接从IoC容器中取即可

为什么叫做控制反转?

控制:指对象的创建(实例化、管理)的权利

反转:控制权交给IoC容器

Spring源码解读笔记_第2张图片

1.2 IoC解决了什么问题

IoC解决了对象之间的耦合问题

Spring源码解读笔记_第3张图片

1.3 IoC和DI的区别

DI全称Dependancy Injection(依赖注入)

IoC和DI描述的是同一件事,只不过角度不一样

Spring源码解读笔记_第4张图片

2. AOP

2.1 什么是AOP

AOP全称Aspect oriented Programming(面向切面编程)

AOP是OOP的一个延续,虽然有了OOP的存在,但是有一些情况是OOP处理不了的,因此AOP出场,AOP独辟蹊径提出横向抽取机制,将横切逻辑代码和业务逻辑代码分离。

Spring源码解读笔记_第5张图片

代码拆分容易,但是如何在不改变原有业务逻辑的情况下,悄无声息的把横切逻辑代码应用到原有的业务逻辑中,达到和原来一样的效果却比较难。

2.2 AOP解决了什么问题

在不改变原有业务逻辑情况下,增强横切逻辑代码,从根本上解耦合,避免横切逻辑代码重复。

2.3 为什么叫做面向切面编程

【切】:指横切逻辑,原有业务逻辑代码不能动的情况下,只能操作横切逻辑代码,所以面向横切逻辑。

【面】:横切逻辑代码往往影响的是很多方法,每一个方法如同一个点,点点成面。

第三部分 手写实现IoC和AOP

1. 银行转账案例问题分析

Spring源码解读笔记_第6张图片

  1. 问题一:service层实现类在使用dao层对象时,直接在TransferService中通过AccountDao accountDao = new AccountDaoImpl获得dao层对象,然而new关键字却将service层和dao层实现类耦合在一起,如果技术架构发生变动,dao层的实现要使用其他技术,切换成本太大,每一个new的地方都需要修改源代码,重新编译,面向接口开发的意义将大打折扣。
  2. 问题二:service层代码没有进行事务控制,如果转账过程中出现异常,将导致数据错乱,后果很严重。

2. 问题解决思路

  • 针对问题一解决方案:把类的全限定名配置在xml中,通过工厂模式,加载配置文件并进行解析,通过反射技术,生产对象。
    • 更进一步,声明一个变量并提供set方法,在反射的时候将所需要的对象注入进去,完成依赖关系维护。
  • 针对问题二解决方案:(1)dao层让两次update操作使用同一个connection对象连接,可以给当前线程绑定一个connection,和当前线程有关系的数据库操作都是用这个connection;(2)把事务控制添加在service层。通过动态代理的方式,获取到service接口的代理类,在进行原有逻辑调用前后添加开启事务,事务提交,异常时事务回滚等;(3)servlet层通过代理工厂获取service的委托对象。

第四部分 Spring IoC的应用

1.Spring IoC基础

Spring源码解读笔记_第7张图片

1.1 BeanFactory与ApplicationContext区别

BeanFactory是Spring框架中IoC容器的顶层接口,只是用来定义一些基础功能和基础规范,而ApplicationContext是它的一个子接口,ApplicationContext具备BeanFactory提供的全部功能。

通常称BeanFactory为Spring IoC的基础容器,ApplicationContext是容器的高级接口,比BeanFactory要拥有更多的功能,比如国际化支持和访问(xml,java配置类)等。

Spring源码解读笔记_第8张图片

启动IoC容器的方式

  • Java环境下启动IoC容器

    • ClassPathXmlApplicationContext:类的根路径下加载配置文件(推荐使用)
    • FileSystemXmlApplicationContext:磁盘路径下加载配置文件
    • AnnotationConfigApplicationContext:纯注解模式下启动Spring容器
  • Web环境下启动IoC容器

    • 从xml启动容器,在web.xml中配置

      
      
      	Archetype Created Web Application
      	
      	
      		contextConfigLocation
      		classpath:applicationContext.xml
      	
      	
      	
      		org.springframework.web.context.ContextLoaderListener
      	
      
      
    • 从配置类启动容器

      
      
      	Archetype Created Web Application
      	
      	
      		contextClass
      		org.springframework.web.context.support.AnnotationConfigWebAppli
      cationContext
      		
      
      	
      	
      		contextConfigLocation
      		com.lagou.edu.SpringConfig
      	
      	
      	
      		org.springframework.web.context.ContextLoaderListener
      	
      
      

1.2 纯xml模式

  • xml文件头

    
    	
    
  • 实例化Bean的三种方式

    • 方式一:使用无参构造函数

      默认情况下,会通过反射调用无参构造函数来创建对象。如果类中没有无参构造函数,将创建失败。

      
      
      
      
    • 方式二:使用静态方法创建

      在实际开发中,我们使用的对象有时候并不是直接通过构造函数就可以创建处理,它可能在创建的过程中会做很多额外的操作。此时会提供一个创建对象的方法,恰好这个方法是static修饰的方法,即是这种情况。

      
      
      

      方式三:使用实例化方法创建

      此种方法和方式二类似,区别是用于获取对象的方法不再是static修饰的,而是类中的普通方法。此种方式比静态方法创建的使用几率高一些。

      
      
      
      
  • Bean的生命周期

    • 作用范围的改变:在Spring框架管理Bean对象的创建时,Bean对象默认是单例,但是它支持配置的方式改变作用范围。

    • 不同作用范围的生命周期

      单例模式:singleton

      对象出生:创建容器是,对象就被创建

      对象活着:容器在,对象就一直存在

      对象死亡:销毁容器,对象就被销毁

      一句话总结:单例模式的bean对象生命周期与容器相同

      多例模式:prototype

      对象出生:使用对象时,创建新的对象实例

      对象活着:对象在使用,就一直存在

      对象死亡:对象长时间不用时,被java的垃圾回收器回收

      一句话总结:多例模式的bean对象,spring只负责创建,不负责销毁

  • Bean的标签属性

    id属性: bean的唯一标识,一个标签内部,标识必须唯一。

    class属性: bean对象的全限定类名。

    name属性: bean的名称,多个名称用空格分隔。

    factory-bean属性: 用于指定创建当前bean对象的工厂bean的唯一标识。指定此属性后class失效

    factory-method属性: 用于指定创建当前bean对象的工厂方法,配合factory-bean属性使用,class属性失效。

    scope属性: bean的作用范围,默认singleton。需使用多例模式时,可配置为prototype。

    init-method属性: bean对象的初始化方法,会在bean对象装配后调用。必须是无参方法。

    destory-method属性: bean对象的销毁方法,会在bean对象销毁前执行。scope为singleton时起作用。

  • DI依赖注入的xml配置

    • 依赖注入分类

      • 按照注入的方式分类

        构造函数注入: 利用带参构造函数实现对类成员的数据赋值。

        set方法注入: 通过类成员的set方法实现数据的注入。(使用最多)

      • 按照注入的数据类型分类

        基本数据类型和String

        注入的数据类型是基本数据类型或者是字符串类型的数据。

        其它Bean类型

        注入的数据类型是对象类型,这个对象时要求出现在IoC容器中的。

        复杂类型(集合类型)

        注入的数据类型是Array,List,Set,Map,Properties中的一种类型。

    • 依赖注入的配置实现之函数注入

      利用构造函数实现对类成员的赋值。

      使用要求:类中提供的构造函数参数个数必须和配置的参数个数一直,且数据类型匹配。

      注意:当无参构造时,则必须提供构造函数参数的注入,否则会报错。

      使用构造函数注入时,涉及的标签时constructor-arg,标签有如下属性:

      name: 用于给构造函数中指定名称的参数赋值。

      index: 用于给构造函数中指定索引位置的参数赋值。

      value: 用于指定基本数据类型或者String类型的数据。

      ref: 用于指定其它Bean类型的数据。

    • 依赖注入的配置实现之set方法注入

      利用字段的set方法实现赋值的注入方式。实际开发中使用最多的注入方式。

      使用set方法注入时,需要使用property标签,标签有如下属性:

      name: 指定注入时调用的set方法名称。(注:不包含set)

      value: 指定注入的数据,支持基本数据类型和String类型。

      ref: 指定注入的数据。支持其它Bean类型。写的是其它Bean的唯一标识。

      • 复杂数据类型注入

        指的是集合数据类型,分为两类,List和Map

        set方法注入:

        List结构的集合数据注入时,array,list,set这三个标签通用,注值的value标签内部可直接写值,也可以使用bean标签配置一个对象,或者用ref标签引用一个已经配过的bean的唯一标识。

        Map结构的集合数据注入时,map标签使用entry子标签实现注入,entry标签可以使用 keyvalue 属性指定存入map中的数据。使用 value-ref 属性指定已经配置好的bean的引用。

1.3 xml与注解相结合模式

注意:

1)实际企业开发中,纯xml模式已经很少使用

2)引入注解功能,不需要引入额外的jar

3)xml+注解结合模式,xml文件依然存在,所以IoC容器的启动依然从加载xml开始

4)第三方jar中的bean定义在xml,自己开发的bean定义使用注解

  • xml中标签与注解的对应(IoC)

    @Component,注解加在类上,针对分层代码开发提供@Controller、@Service、

    @Repository分别用于控制层、服务层、dao层的bean的定义。用法一样,只是为了清晰区分。

  • DI依赖注入的注解实现方式

    @Autowired(推荐使用):采取的策略为按照类型注入。

    @Resource:默认安装ByName自动注入。

    • 如果同时指定了name和type,则从Spring 上下文中找到唯一匹配的bean进行装配,找不到抛出异常。
    • 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到抛出异常。
    • 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
    • 如果既没有指定name,又没有指定type,则自动安装byName方式进行装配;

    注意:@Resource在JDK 11中已经移除,如需使用,需单独引入jar包

    
    	javax.annotation
    	javax.annotation-api
    	1.3.2
    
    

1.4 纯注解模式

改造xml+注解模式,将xml中遗留的内容全部以注解的形式迁移出去,最终删除xml,从java配置类启动。

对应注解

@Configuration注解,表名当前类是配置类

@ComponentScan注解,替代context:component-scan

@PropertySource,引入外部属性配置文件

@Import引入其他配置类

@Value对变量赋值,可以直接赋值,也可以使用${}读取资源配置文件中的信息。

@Bean将方法返回对象加入Spring IoC容器

2. Spring IoC高级特性

2.1 lazy-init延迟加载

Bean的延迟加载(延迟创建)


该bean默认的设置为:

lazy-init=“false”,立即加载,表示在spring启动时,立刻进行实例化。

如果不想让Bean在ApplicationContext实现初始化时被提前实例化,可将lazy-init设置为true。

设置lazy-init为true的bean将不会在ApplicationContext启动时提前被实例化,而是第一次向容器通过getBean索取bean时实例化的。

应用场景

(1)开启延迟加载一定程度提高容器启动和运转性能。

(2)对于不常使用的Bean设置延迟加载,这样偶尔使用的时候再加载,不必要从一开始该Bean就占用资源

2.2 FactoryBean 和 BeanFactory

BeanFactory接口是容器的顶级接口,定义了容器的一些基础行为,负责生产和管理Bean的一个工厂,具体使用它下面的子接口类型(如ApplicationContext)

Spring中Bean有两种,一种是普通Bean,一种是工厂Bean(FactoryBean),FactoryBean可以生成某一个类型的Bean实例,也就是说我们可以借助它自定义Bean的创建过程。

Bean创建的三种方式中的静态方法和实例化方法和FactoryBean作用类似,FactoryBean使用较多。

2.3 后置处理器

Spring提供了两种后置处理Bean的扩展接口,分别为BeanPostProcessor和BeanFactoryPostProcessor

工厂初始化(BeanFactory)—>Bean对象

在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做一些事情

在Bean对象实例化(Bean的生命周期还没有完成)之后可以使用BeanPostProcessor进行后置处理做一些事情

注意:对象不一定是Spring Bean,Spring Bean一定是对象。

  • BeanPostProcessor

    BeanPostProcessor是针对Bean级别的处理,可以针对具体的Bean,该接口提供两个方法,分别在Bean的初始化方法前后执行,初始化方法类似于init-method指定的方法。

    public interface BeanPostProcessor {
    
    	@Nullable
    	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		return bean;
    	}
    
    	@Nullable
    	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		return bean;
    	}
    
    }
    

    定义一个类实现BeanPostProcessor,默认对整个Spring容器中所有Bean进行处理,如对具体某个Bean处理,可通过方法参数判断,两个参数分别为Object和String,参数一:bean实例,参数二:bean的name或id

    注意:处理是发生在Spring容器的实例化和依赖注入之后。

  • BeanFactoryPostProcessor

    BeanFactory级别的处理,针对整个Bean的工厂进行处理,典型应用:PropertyPlaceholderConfigurer,此接口只提供了一个方法,方法参数为:ConfigurableListableBeanFactory,该参数定义了一些方法,如getBeanDefinition,可根据此方法,找到定义bean的BeanDefinition对象(可进行修改)

    BeanDefinition对象: xml中定义的bean标签,Spring解析bean标签成为一个JavaBean(就是BeanDefinition)

第五部分 Spring IoC源码深度剖析

  • 好处:提高培养代码架构思维、深入理解框架
  • 原则
    • 定焦原则:主线
    • 宏观原则:关注源码结构和业务流程,淡化具体代码细节
  • 读源码的方法和技巧
    • 断点(调用栈)
    • 反调(Find Usages)
    • 经验(Spring框架中doXXX,做具体处理的地方)

1. Spring IoC容器初始化主题流程

1.1 Spring IoC的容器体系

IoC容器是Spring的核心模块,是抽象了对象管理、依赖关系管理的框架解决方案。提供了很多容器,其中BeanFactory是顶级容器,不能被实例化。

BeanFactory顶级接口方法栈如下:

Spring源码解读笔记_第9张图片

1.2 Bean生命周期关键时机点

Spring的生命周期

构造器执行、初始化方法执行、Bean后置处理器的before/after方法:AbstractApplicationContext#refresh#finishBeanFactoryInitialization

Bean工厂后置处理器初始化、方法执行:

AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors

Bean后置处理器初始化:AbstractApplicationContext#refresh#registerBeanPostProcessors

关键点 触发代码
构造器 refresh#finishBeanFactoryInitialization
BeanFactoryPostProcessor初始化 refresh#invokeBeanFactoryPostProcessors
BeanFactoryPostProcessor方法调用 refresh#invokeBeanFactoryPostProcessors
BeanPostProcessor初始化 refresh#registerBeanPostProcessors
BeanPostProcessor方法调用 refresh#finishBeanFactoryInitialization

1.3 Spring IoC容器初始化主体流程

Spring IoC容器初始化的关键环节就在AbstractApplicationContext#refresh() 方法中。

@Override
public void refresh() throws BeansException, IllegalStateException {
	// 对象锁加锁
	synchronized (this.startupShutdownMonitor) {
		// 1.刷新前的预处理
		prepareRefresh();

		// 2.获取BeanFactory;默认实现是DefaultListableBeanFactory,加载BeanDefition 并注册到 BeanDefitionRegistry
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// 3.BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器等)
		prepareBeanFactory(beanFactory);

		try {
			// 4.BeanFactory准备工作完成后进行的后置处理工作
			postProcessBeanFactory(beanFactory);

			// 5.实例化实现了BeanFactoryPostProcessor接口的Bean,并调用接口方法
			invokeBeanFactoryPostProcessors(beanFactory);

			// 6.注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行
			registerBeanPostProcessors(beanFactory);

			// 7.初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
			initMessageSource();

			// 8.初始化事件派发器
			initApplicationEventMulticaster();

			// 9.子类重写这个方法,在容器刷新的时候可以自定义逻辑;
			onRefresh();

			// 10.注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean
			registerListeners();

			/*
				11.初始化所有剩下的非懒加载的单例bean
				初始化创建非懒加载方式的单例Bean实例(未设置属性)
				填充属性
				初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)
				调用BeanPostProcessor(后置处理器)对实例bean进行后置处理
			 */
			finishBeanFactoryInitialization(beanFactory);

			/*
				12.完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent)
			 */
			finishRefresh();
		}

		...
	}
}	

2. BeanFactory创建流程

2.1 获取BeanFactory子流程

Spring源码解读笔记_第10张图片

2.28 BeanDefinition加载解析及注册子流程

(1)该子流程涉及以下几个关键步骤

  • Resource定位: 对BeanDefinition的资源定位过程。(找到定义Java Bean信息的xml文件,封装成Resource对象)

  • BeanDefinition载入: 将用户定义好的Java Bean表示为IoC容器内部的数据结构(BeanDefinition)

  • 注册BeanDefinition到IoC容器

(2)过程分析

  • 子流程入口在AbstractRefreshableApplicationContext#refreshBeanFactory方法中

loadBeanDefinitions方法

/*
 * 对 bean factory 执行刷新操作,关闭以前的 bean factory(如果有)
 * 并且为 context 初始化一个新的 bean factory
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
	...
	try {
		// 实例化 DefaultListableBeanFactory
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		...
		// 加载应用中的BeanDefinitions
		loadBeanDefinitions(beanFactory);
		synchronized (this.beanFactoryMonitor) {
			// 赋值当前bean facotry
			this.beanFactory = beanFactory;
		}
	}
	catch (IOException ex) {
		...
	}
}
  • 依次调用多个类的loadBeanDefinitions方法—>AbstractXmlApplicationContext—>AbstractBeanDefinitionReader—>XmlBeanDefinitionReader一直执行到XmlBeanDefinitionReaderdoLoadBeanDefinitions方法

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    	...
    	try {
    		InputStream inputStream = encodedResource.getResource().getInputStream();
    		try {
    			// 把xml文件流封装为InputSource对象
    			InputSource inputSource = new InputSource(inputStream);
    			if (encodedResource.getEncoding() != null) {
    				inputSource.setEncoding(encodedResource.getEncoding());
    			}
    			// do!执行加载逻辑
    			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    		}
    		finally {
    			...
    		}
    	}
    	catch (IOException ex) {
    		...
    	}
    	finally {
    		...
    	}
    }
    
  • 重点观察XmlBeanDefinitionReader类的registerBeanDefinitions方法,此处关注createRederContext方法和DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法,可以看到,Spring首先完成了NamespaceHandlerResolver的初始化。

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    	...
    	// 注册BeanDefinition
    	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    	...
    }
    
    public XmlReaderContext createReaderContext(Resource resource) {
    	return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
    			this.sourceExtractor, this, getNamespaceHandlerResolver());
    }
    

    进入registerBeanDefinitions方法中追踪,调用了DefaultBeanDefinitionDocumentReader#registerBeanDefinitions方法,进入doRegisterBeanDefinitions方法,调用了parseBeanDefinitions方法

    protected void doRegisterBeanDefinitions(Element root) {
    	...
    	parseBeanDefinitions(root, this.delegate);
    	...
    }
    

    进入parseBeanDefinitions方法,可以看到又调用了parseDefaultElement,这个方法是负责解析默认标签元素的。

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    	...
    				
    	// 解析默认标签元素
    	parseDefaultElement(ele, delegate);
    				
    	// 解析自定义标签元素
    	delegate.parseCustomElement(ele);
    		
    	...
    }
    

    进入parseDefaultElement可以看到又调用了processBeanDefinition,此方法负责解析bean元素为BeanDefinition,通过BeanDefinitionReaderUtils.registerBeanDefinition完成注册。

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    	// 解析bean元素为BeanDefinition,但是此时使用 BeanDefinitionHolder 又包装成了 BeanDefinitionHolder 对象
    	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    	if (bdHolder != null) {
    		...
    		try {
    			// 完成BeanDefinition的注册
    			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    		}
    		catch (BeanDefinitionStoreException ex) {
    			...
    		}
    		...
    	}
    }
    

    至此,注册流程结束,所谓的注册就是把封装的xml中定义的Bean信息封装为BeanDefinition对象之后放入一个map中。

    (3)时序图

Spring源码解读笔记_第11张图片

3. Bean创建过程

  • 通过最开始的关键时机点分析,Bean的创建子流程入口在AbstractApplicationContext#refresh()⽅法的finishBeanFactoryInitialization(beanFactory)

    /*
    	Instantiate all remaining (non-lazy-init) singletons.
    	初始化所有剩下的非懒加载的单例bean
    	初始化创建非懒加载方式的单例Bean实例(未设置属性)
    	填充属性
    	初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)
    	调用BeanPostProcessor(后置处理器)对实例bean进行后置处理
     */
    finishBeanFactoryInitialization(beanFactory);
    
  • 进⼊finishBeanFactoryInitialization

    /**
     * 结束 bean factory 的初始化工作
     * 实例化所有单例bean
     */
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    	...
    	beanFactory.setTempClassLoader(null);
    
    	// Allow for caching all bean definition metadata, not expecting further changes.
    	beanFactory.freezeConfiguration();
    
    	// Instantiate all remaining (non-lazy-init) singletons.
    	// 实例化所有立即加载的单例bean
    	beanFactory.preInstantiateSingletons();
    }
    
  • 继续进⼊DefaultListableBeanFactory类的preInstantiateSingletons⽅法,可以看到工厂Bean或者普通Bean,最终都是通过getBean的方法获取实例。

    // 触发所有非延迟加载单例bean的初始化,主要步骤为getBean
    for (String beanName : beanNames) {
    	// 合并父BeanDefinition对象
    	// map.get(beanName)
    	RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    	if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    		if (isFactoryBean(beanName)) {
    			Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
    			// 如果是FactoryBean则加&
    			if (bean instanceof FactoryBean) {
    				final FactoryBean<?> factory = (FactoryBean<?>) bean;
    				boolean isEagerInit;
    				if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
    					isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
    									((SmartFactoryBean<?>) factory)::isEagerInit,
    							getAccessControlContext());
    				}
    				else {
    					isEagerInit = (factory instanceof SmartFactoryBean &&
    							((SmartFactoryBean<?>) factory).isEagerInit());
    				}
    				if (isEagerInit) {
    					getBean(beanName);
    				}
    			}
    		}
    		else {
    			// 实例化当前bean
    			getBean(beanName);
    		}
    	}
    }
    
  • 继续跟踪下去,进⼊到了AbstractBeanFactory类的doGetBean⽅法,找到核心部分

    // 创建单例bean
    if (mbd.isSingleton()) {
    	sharedInstance = getSingleton(beanName, () -> {
    		try {
    			// 创建 bean
    			return createBean(beanName, mbd, args);
    		}
    		catch (BeansException ex) {
    			destroySingleton(beanName);
    			throw ex;
    		}
    	});
    	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    
  • 接着进入到AbstractAutowireCapableBeanFactory类的doCreateBean方法

    try {
    	// 进入,真真正正创建bean
    	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    	return beanInstance;
    }
    
  • 进入doCreateBean方法,重点关注两块重点区域

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    			throws BeanCreationException {
    
    	...
    	if (instanceWrapper == null) {
    		// 创建 Bean 实例,仅仅调用构造方法,但是尚未设置属性
    		instanceWrapper = createBeanInstance(beanName, mbd, args);
    	}
    	...
    
    	// 初始化bean实例
    	Object exposedObject = bean;
    	try {
    		// Bean属性填充
    		populateBean(beanName, mbd, instanceWrapper);
    		// 调用初始化方法,应用BeanPostProcessor后置处理器
    		exposedObject = initializeBean(beanName, exposedObject, mbd);
    	}
    	...
    }
    

4. lazy-init 延迟加载机制原理

  • lazy-init 延迟加载机制分析

普通 Bean 的初始化是在容器启动初始化阶段执⾏的,⽽被lazy-init=true修饰的 bean 则是在从容器⾥
第⼀次进⾏context.getBean() 时进⾏触发。Spring 启动的时候会把所有bean信息(包括XML和注解)解
析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个
BeanDefinition 进⾏处理,如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进⾏初始化并依赖注⼊。

public void preInstantiateSingletons() throws BeansException {
	// 所有bean的名字
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	// 触发所有非延迟加载单例bean的初始化,主要步骤为getBean
	for (String beanName : beanNames) {
		// 合并父BeanDefinition对象
		// map.get(beanName)
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				// 如果是FactoryBean则加&
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
										((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				/*
				如果是普通bean则进⾏初始化并依赖注⼊,此 getBean(beanName)接下来触发的逻辑
				和
				懒加载时 context.getBean("beanName") 所触发的逻辑是一样的
				*/
				getBean(beanName);
			}
		}
	}

	...
}
  • 总结:

    • 对于被修饰为lazy-init的bean,Spring容器初始化阶段不会进行init并且依赖注入,当第一次调用getBean的时候才进行初始化并依赖注入

    • 对于非懒加载的bean,getBean的时候会从缓存里取,因为容器初始化阶段bean已经初始化完成并且放入缓存中

5. Spring IoC循环依赖问题

5.1 什么是循环依赖

循环依赖就是循环引用,也就是两个或两个以上的Bean互相持有对方,最终形成闭环。

注意:这里不是函数的循环调用,而是对象的相互依赖关系。

Spring中循环依赖场景有:

  • 构造器的循环依赖(构造器注入)
  • Field属性的循环依赖(set注入)

5.2 循环依赖处理机制

  • 单例bean构造器参数循环依赖(无法解决)

  • propotype原型bean循环依赖(无法解决)

    总结:Spring不支持原型bean的循环依赖

  • 单例bean通过setXXX或者使用**@Autowired**进行循环依赖

    Spring的循环依赖的理论依据基于java的引用传递,当获得对象的引用时,对象的属性是可以延后设置的,但是构造器必须是在获取引用之前

    Spring通过setXXX或者使用@Autowired方法解决循环依赖其实是通过提前暴露一个ObectFactory对象来完成的,简单来说ClassA在调用构造器完成对象初始化之后,在调用ClassA的setClassB方法之前,就把ClassA实例化的对象通过ObjectFactory提前暴露到Spring容器中

    • Spring容器初始化ClassA通过构造器初始化对象后提前暴露到Spring容器

      //将初始化后的对象提前已ObjectFactory对象注⼊到容器中
      addSingletonFactory(beanName, new ObjectFactory() {
      	@Override
      	public Object getObject() throws BeansException {
      		return getEarlyBeanReference(beanName, mbd, bean);
      	}
      });
        
           
    • ClassA调用setClassB方法,Spring首先尝试从容器中获取ClassB,此时ClassB不存在容器中

    • Spring容器初始化ClassB,同时也会将ClassB提前暴露到Spring容器中

    • ClassB调用setClassA方法,Spring从容器中获取ClassA,因为第一步已经提前暴露ClassA到容器中,因此可以获取ClassA实例

    • ClassA通过Spring容器获取到ClassB,完成了对象初始化操作

    • 这样ClassA和ClassB都完成了对象初始化操作,解决了循环依赖问题

    • 时序图
      Spring源码解读笔记_第12张图片

    • 第六部分 Spring AOP应用

      AOP本质:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、日志代码、事务控制代码、性能监控代码。

      1. AOP相关术语

      1.1 相关术语

      名词 解释
      Joinpoint(连接点) 指那些可以用于把增强代码加入到业务主线中的点(方法)
      Pointcut(切点) 指那些已经把增强代码加入到业务主线进来之后的连接点
      Advice(通知/增强) 指切面类中用于提供增强功能的方法,并且不同的方法增强的时机是不一样的
      Target(目标对象) 指代理的目标对象
      Proxy(代理) 指一个类被AOP织入增强后,产生的代理类(代理对象)
      Weaving(织入) 指把增强应用到目标对象来创建新的代理对象的过程
      Aspect(切面) 指增强的代码所关注的方面,把这些相关的增强代码定义到一个类中,这个类就是切面类

      连接点:方法开始时、结束时、正常运行完毕时、方法异常时等这些特殊的时机点,称之为连接点

      切入点:指定AOP想要影响的具体方法

      Advice增强:

      第一个层次:横切逻辑

      第二个层次:方位点(在某一些连接点加入横切逻辑,那么这些连接点就叫做方位点,描述的是具体的特殊时机)

      Aspects切面:切面就是对上述概念的综合

      Aspects切面 = 切入点(锁定方法)+ 方位点(锁定方法中的特殊时机)+ 横切逻辑

      2. Spring中AOP的代理选择

      Spring实现AOP思想,使用的是动态代理技术

      默认情况下,Spring会根据被代理对象是否实现接口来选择使用JDK还是CGLIB。当被代理对象没有实现任何接口时,Spring会选择CGLIB。当被代理对象实现了接口,Spring会选择JDK官方的代理技术,可以通过配置的方式,让Spring强制使用CGLIB。

      3. Spring中AOP的配置方式

      在Spring的AOP配置中,支持3类配置方式

      第一类:使用XML配置

      第二类:使用XML + 注解组合配置

      第三类:使用纯注解配置

      4. Spring中AOP实现

      4.1 XML模式

      需要引入aop的jar包

      • 坐标
      <dependency>
      	<groupId>org.springframework</groupId>
      	<artifactId>spring-aop</artifactId>
      	<version>5.1.12.RELEASE</version>
      </dependency>
      <dependency>
      	<groupId>org.aspectj</groupId>
      	<artifactId>aspectjweaver</artifactId>
      	<version>1.9.4</version>
      </dependency>
      
      • AOP核心配置
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              https://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/aop
              https://www.springframework.org/schema/aop/spring-aop.xsd
      ">
      
          <bean id="logUtils" class="com.lagou.edu.utils.LogUtils"></bean>
          <aop:config>
              <aop:aspect id="logAspect" ref="logUtils">
                  <aop:pointcut id="pt1"
                                expression="execution(void com.lagou.edu.service.impl.TransferServiceImpl.transfer(java.lang.String, java.lang.String, java.math.BigDecimal))"/>
                  <aop:before method="before" pointcut-ref="pt1"/>
                  <aop:after method="after" pointcut-ref="pt1"/>
                  <aop:around method="around" pointcut-ref="pt1"/>
                  <aop:after-throwing method="expection" pointcut-ref="pt1"/>
              </aop:aspect>
          </aop:config>
      </beans>
      
      • 细节

        • 关于切入点表达式

          上述配置实现了对TransferServiceImpltransfer方法进行增强,执行之前,输出了记录日志的语句。这里使用到了切入点表达式

          • 概念及作用

            切入点表达式,也称为AspectJ切入点表达式,指的是遵循特定语法结构的字符串,其作用是用于对符合语法格式的连接点进行增强。

          • 关于AspectJ

            AspectJ是一个机遇Java语言的AOP框架,Spring框架从2.0版本之后集成了AspectJ框架中切入点表达式的部分,开始支持AspectJ切入点表达式

          • 切入点表达式使用示例

            全限定方法名 访问修饰符 返回值 包名.类名.方法名(参数列表)
            全匹配方式: public void com.lagou.edu.service.impl.TransferServiceImpl.transfer(java.lang.String, java.lang.String, java.math.BigDecimal)
            简化后:* *..*.*(*) 参数列表可以使用*,表示任意参数类型,但是必须有参数
            全匹配方式:* *..*.*(..) 参数列表可以使用..,表示有误参数均可,参数可以是任意类型
            
        • 改变代理方式的配置

          • 使用aop:config配置标签

            <aop:config proxy-target-class="true">
            
          • 使用aop:aspectj-autoproxy标签配置

            
            
            
        • 五种通知类型

          • 前置通知

            配置方式:aop:before标签

            <aop:before method="printLog" pointcut-ref="pointcut1">
            </aop:before>
            

            执行时机:前置通知永远都会在切入点方法(业务核心方法)执行前执行

            细节:前置通知可以获取切入点方法的参数,对其进行增强

          • 正常执行时通知

            配置方式:aop:after-returning标签

            <aop:after-returning method="afterReturningPrintLog" pointcut-
            ref="pt1"></aop:after-returning>
            
          • 异常通知

            配置方式:aop:after-throwing标签

            
            

            执行时机:异常通知的执行时机是在切入点方法执行产生异常之后,异常通知执行。如果切入点方法执行时没有产生异常,则异常通知不会执行

            细节:异常通知不仅可以获取切入点方法执行的参数,也可以获取切入点方法执行产生的异常信息

          • 最终通知

            配置方式:aop:after标签

            
            

            执行时机:最终通知的执行时机是在切入点方法执行完成之后,切入点方法返回之前执行。无论切入点方法执行是否产生异常,它都会在返回之前执行。

            细节:最终通知执行时,可以获取到通知方法的参数,同时它可以做一些清理操作。

          • 环绕通知

            配置方式:aop:around标签

            
            

            **特此说明:**环绕通知,有别于前面四种通知类型外的特殊通知。前面四种通知(前置、后置、异常和最终),它们都是指定何时增强的通知类型。而环绕通知,它是Spring框架提供的一种通过编码的方式,控制增强代码何时执行的通知类型。

      4.2 XML + 注解模式

      • XML中开启Spring对AOP注解的支持

        
        
        
      • 示例

        @Component
        @Aspect
        public class LogUtils {
        
            @Pointcut("execution(* com.lagou.service.impl.*.*(..))")
        	public void pointcut(){}
        
            @Before("pointcut()")
        	public void beforePrintLog(JoinPoint jp){
        		Object[] args = jp.getArgs();
        		System.out.println("前置通知:beforePrintLog,参数是:"+
        		Arrays.toString(args));
        	}
        
            @AfterReturning(value = "pointcut()",returning = "rtValue")
        	public void afterReturningPrintLog(Object rtValue){
        		System.out.println("后置通知:afterReturningPrintLog,返回值
        		是:"+rtValue);
        	}
        
            @AfterThrowing(value = "pointcut()",throwing = "e")
        	public void afterThrowingPrintLog(Throwable e){
        		System.out.println("异常通知:afterThrowingPrintLog,异常是:"+e);
        	}
        
            @After("pointcut()")
        	public void afterPrintLog(){
        		System.out.println("最终通知:afterPrintLog");
        	}                       
                                   
            @Around("pointcut()")
            public Object aroundPrintLog(ProceedingJoinPoint proceedingJoinPoint) {
                //定义返回值
        		Object rtValue = null;
        		try{
        			//前置通知
        			System.out.println("前置通知");
        			//1.获取参数
        			Object[] args = pjp.getArgs();
                    //2.执⾏切⼊点⽅法
        			rtValue = pjp.proceed(args);
        			//后置通知
        			System.out.println("后置通知");
            	}catch (Throwable t){
        			//异常通知
        			System.out.println("异常通知");
        			t.printStackTrace();
        		}finally {
        			//最终通知
        			System.out.println("最终通知");
        		}
        		return rtValue;
            }
        }
        

      4.3 注解模式

      在使⽤注解驱动开发aop时,我们要明确的就是,是注解替换掉配置⽂件中的下⾯这⾏配置:

      <!--开启spring对注解aop的⽀持-->
      <aop:aspectj-autoproxy/>
      

      配置类使用注解进行替换上诉配置

      @Configuration
      @ComponentScan("com.lagou")
      @EnableAspectJAutoProxy //开启spring对注解AOP的⽀持
      public class SpringConfiguration {
      }
      

      5. Spring声明式事务的支持

      编程式事务:业务代码中添加事务控制代码,叫做编程式事务

      声明式事务:通过xml或注解的方式达到控制事务的目的,叫做声明式事务

      5.1 事务回顾

      5.1.1 事务的概念

      事务:指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不执行。从而确保数据的准确与安全。

      5.1.2 事务的四大特性

      原子性: 指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生

      一致性: 事务必须使数据库从一个一致性状态变换到另一个一致性状态

      例如:A给B转账,转账前,A有1000,B有1000,转账后A+B必须是2000

      隔离性: 指多个用户并发访问数据库时,数据库为每一个用户开启的事务,每个事务不能被其他事务的操作数据所干扰,多个并发事务之间相互隔离

      持久性: 指一个事务一旦被提交,它对数据库的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

      5.1.3 事务的隔离级别

      不考虑隔离级别,会出行以下情况,也即为隔离级别在解决事务并发问题

      脏读:一个线程中的事务读到了另一个线程中未提交的数据

      不可重复读:一个线程中的事务读到了另一个线程中已经提交的update的数据

      虚读:一个线程中的事务读到了另一个线程中已提交的insert或者delete的数据

      数据库工定义了四种隔离级别:

      隔离级别 说明 等级
      Serializable(串⾏化) 可避免脏读、不可重复读、虚读情况的发⽣。(串⾏化) 最⾼
      Repeatable read(可重复读) 可避免脏读、不可重复读情况的发⽣。(幻读有可能发⽣) 第⼆
      该机制下会对要update的⾏进⾏加锁
      Read committed(读已提交) 可避免脏读情况发⽣。不可重复读和幻读⼀定会发⽣。 第三
      Read uncommitted(读未提交) 最低级别,以上情况均⽆法保证。(读未提交) 最低

      注意:级别依次升高,效率依次降低

      5.1.4 事务的传播行为

      事务往往在service层进行控制,如果出行service方法A调用了另一个service层的方法B,A和B自身都已经被添加了事务控制,那么A调用B的时候,就需要进行事务的一些协商,这就叫做事务的传播行为。

      PROPAGATION_REQUIRED 如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加入到这个事务中。这是最常⻅的选择。
      PROPAGATION_SUPPORTS ⽀持当前事务,如果当前没有事务,就以非事务方式执行。
      PROPAGATION_MANDATORY 使⽤当前的事务,如果当前没有事务,就抛出异常。
      PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
      PROPAGATION_NOT_SUPPORTED 以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。
      PROPAGATION_NEVER 以⾮事务⽅式执⾏,如果当前存在事务,则抛出异常。
      PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执⾏。如果当前没有事务,则
      执⾏与PROPAGATION_REQUIRED类似的操作。

      5.2 Spring声明式事务配置

      • 纯xml模式

        导入jar包

        <dependency>
        	<groupId>org.springframework</groupId>
        	<artifactId>spring-context</artifactId>
        	<version>5.1.12.RELEASE</version>
        </dependency>
        
        <dependency>
        	<groupId>org.aspectj</groupId>
        	<artifactId>aspectjweaver</artifactId>
        	<version>1.8.13</version>
        </dependency>
        
        <dependency>
        	<groupId>org.springframework</groupId>
        	<artifactId>spring-tx</artifactId>
        	<version>5.1.12.RELEASE</version>
        </dependency>
        
        <dependency>
        	<groupId>org.springframework</groupId>
        	<artifactId>spring-jdbc</artifactId>
        	<version>5.1.12.RELEASE</version>
        </dependency>
        

        xml配置

        <tx:advice id="txAdvice" transaction-manager="transactionManager">
        	<tx:attributes>
        		<tx:method name="*" read-only="false"/>
        		<tx:method name="select*" read-only="true"/>
        	</tx:attributes>
        </tx:advice>
        <aop:config>
        	<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))"></aop:advisor>
        </aop:config>
        
      • xml + 注解模式

        • xml配置
        <!--配置事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        	<property name="dataSource" ref="dataSource"/>
        </bean>
        
        <!--开启spring对注解事务的支持-->
        <tx:annotation-driven transaction-manager="transactionManager"/>
        
        • 接口、类或方法上添加@Transactional注解
        @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
        
      • 纯注解模式

        Spring 的配置类上添加 @EnableTransactionManagement 注解即可

        @EnableTransactionManagement//开启spring注解事务的⽀持
        public class SpringConfiguration {
        }
        

      第七部分 AOP源码深度剖析

      1. 代理对象创建

      1.1 代理对象创建流程

      入口:AbstractAutowireCapableBeanFactory#initializeBean

      protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
      	...
      	if (mbd == null || !mbd.isSynthetic()) {
      		// 整个Bean初始化完成,执⾏后置处理器⽅法
      		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
      	}
      
      	return wrappedBean;
      }
      

      进入applyBeanPostProcessorsAfterInitialization方法

      public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      			throws BeansException {
      
      	Object result = existingBean;
      	// 循环执行后置处理器
      	for (BeanPostProcessor processor : getBeanPostProcessors()) {
      		Object current = processor.postProcessAfterInitialization(result, beanName);
      		if (current == null) {
      			return result;
      		}
      		result = current;
      	}
      	return result;
      }
      

      创建代理对象的后置处理器AbstractAutoProxyCreator#postProcessAfterInitialization

      public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
      	if (bean != null) {
      		// 检查下该类是否已经暴露过了(可能已经创建了,比如A依赖B时,创建A时候,就会先去创建B。
      			// 当真正需要创建B时,就没必要再代理⼀次已经代理过的对象),避免重复创建
      		Object cacheKey = getCacheKey(bean.getClass(), beanName);
      		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
      			return wrapIfNecessary(bean, beanName, cacheKey);
      		}
      	}
      	return bean;
      }
      

      进入wrapIfNecessary方法

      protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
      	...
      
      	// Create proxy if we have advice.
      	// 查找出和当前bean匹配的advisor
      	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
      	if (specificInterceptors != DO_NOT_PROXY) {
      		this.advisedBeans.put(cacheKey, Boolean.TRUE);
      		// 创建代理对象
      		Object proxy = createProxy(
      				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      		this.proxyTypes.put(cacheKey, proxy.getClass());
      		return proxy;
      	}
      
      	this.advisedBeans.put(cacheKey, Boolean.FALSE);
      	return bean;
      }
      

      进入createProxy方法

      protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
      			@Nullable Object[] specificInterceptors, TargetSource targetSource) {
      
      	if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      		AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
      	}
      
      	// 创建代理的工作交给ProxyFactory
      	ProxyFactory proxyFactory = new ProxyFactory();
      	proxyFactory.copyFrom(this);
      
      	// 判断是否要设置proxyTargetClass为true
      	if (!proxyFactory.isProxyTargetClass()) {
      		if (shouldProxyTargetClass(beanClass, beanName)) {
      			proxyFactory.setProxyTargetClass(true);
      		}
      		else {
      			evaluateProxyInterfaces(beanClass, proxyFactory);
      		}
      	}
      
      	// 把增强和通用拦截器对象合并,都适配成Advisor
      	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
      	proxyFactory.addAdvisors(advisors);
      	// 设置参数
      	proxyFactory.setTargetSource(targetSource);
      	customizeProxyFactory(proxyFactory);
      
      	proxyFactory.setFrozen(this.freezeProxy);
      	if (advisorsPreFiltered()) {
      		proxyFactory.setPreFiltered(true);
      	}
      	// 准备工作做完就开始创建代理
      	return proxyFactory.getProxy(getProxyClassLoader());
      }
      

      接着跟进ProxyFactory

      public Object getProxy(@Nullable ClassLoader classLoader) {
      	// 用ProxyFactory创建AopProxy, 然后用AopProxy创建Proxy, 所以这里重要的是看获取的AopProxy
      	
      	// 对象是什么,
      	// 然后进去看怎么创建动态代理, 提供了两种:jdk proxy, cglib
      	return createAopProxy().getProxy(classLoader);
      }
      

      流程就是用AopProxyFactory创建AopProxy,再用AopProxy创建代理对象,这里的AopProxyFactory默认是DefaultAopProxyFactory,看它的createAopProxy⽅法

      public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      		Class<?> targetClass = config.getTargetClass();
      		...
      		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
      			return new JdkDynamicAopProxy(config);
      		}
      		return new ObjenesisCglibAopProxy(config);
      	}
      	else {
      		return new JdkDynamicAopProxy(config);
      	}
      }
      

      这里决定创建代理对象时用JDK还是用CGLIB,最简单的从使用方面来说:设置proxyTargetClass=true强制使用CGLIB代理,什么参数都不设置并且对象类实现接口则默认用JDK代理,如果没有实现接口则也必须使用CGLIB

      • 时序图

      Spring源码解读笔记_第13张图片

      2. Spring声明式事务控制

      2.1 @EnableTransactionManagement

      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Import(TransactionManagementConfigurationSelector.class)
      public @interface EnableTransactionManagement {
      
      	// true:使用CGLIB代理,false:使用JDK代理
      	boolean proxyTargetClass() default false;
      
      	AdviceMode mode() default AdviceMode.PROXY;
      
      	int order() default Ordered.LOWEST_PRECEDENCE;
      
      }
      

      @EnableTransactionManagement 注解使⽤ @Import 标签引⼊了
      TransactionManagementConfigurationSelector类,这个类⼜向容器中导⼊了两个重要的组件

      protected String[] selectImports(AdviceMode adviceMode) {
      	switch (adviceMode) {
      		case PROXY:
      			return new String[] {AutoProxyRegistrar.class.getName(),
      					ProxyTransactionManagementConfiguration.class.getName()};
      		case ASPECTJ:
      			return new String[] {determineTransactionAspectClass()};
      		default:
      			return null;
      	}
      }
      

      2.2 加载事务控制组件

      • AutoProxyRegistrar

        AutoProxyRegistrar类的registerBeanDefinitions方法中又注册了一个组件

        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        		boolean candidateFound = false;
        		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
        		for (String annType : annTypes) {
        			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
        			if (candidate == null) {
        				continue;
        			}
        			Object mode = candidate.get("mode");
        			Object proxyTargetClass = candidate.get("proxyTargetClass");
        			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
        					Boolean.class == proxyTargetClass.getClass()) {
        				candidateFound = true;
        				if (mode == AdviceMode.PROXY) {
        					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
        					if ((Boolean) proxyTargetClass) {
        						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        						return;
        					}
        				}
        			}
        		}
        		...
        	}
        

        进入AopConfigUtils.registerAutoProxyCreatorIfNecessary方法

        public static BeanDefinition registerAutoProxyCreatorIfNecessary(
        			BeanDefinitionRegistry registry, @Nullable Object source) {
        
        	return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
        }
        

        最终发现,注册了⼀个叫做 InfrastructureAdvisorAutoProxyCreator 的 Bean,而这个类是

      AbstractAutoProxyCreator 的⼦类,实现了SmartInstantiationAwareBeanPostProcessor接⼝,说明这是一个后置处理器,而且跟spring AOP 开启@EnableAspectJAutoProxy时注册的 AnnotationAwareAspectJProxyCreator实现的是同⼀个接⼝,所以说,声明式事务是 springAOP 思想的⼀种应用。

      • ProxyTransactionManagementConfiguration组件

        @Configuration
        public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
        
        	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
        	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
        		// 事务增强器
        		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        		// 向事务增强器中注入 属性解析器 transactionAttributeSource
        		advisor.setTransactionAttributeSource(transactionAttributeSource());
        		// 向事务增强器中注入 事务拦截器 transactionInterceptor
        		advisor.setAdvice(transactionInterceptor());
        		if (this.enableTx != null) {
        			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        		}
        		return advisor;
        	}
        
        	@Bean
        	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        	// 属性解析器 transactionAttributeSource
        	public TransactionAttributeSource transactionAttributeSource() {
        		return new AnnotationTransactionAttributeSource();
        	}
        
        	@Bean
        	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        	// 事务拦截器 transactionInterceptor
        	public TransactionInterceptor transactionInterceptor() {
        		TransactionInterceptor interceptor = new TransactionInterceptor();
        		interceptor.setTransactionAttributeSource(transactionAttributeSource());
        		if (this.txManager != null) {
        			interceptor.setTransactionManager(this.txManager);
        		}
        		return interceptor;
        	}
        
        }
        

        ProxyTransactionManagementConfiguration是一个容器配置类,注册了一个组件transactionAdvisor,称为事务增强器,然后再这个事务增强器中又注入了两个属性:

        transactionAttributeSource属性解析器,和transactionInterceptor事务拦截器

        • 属性解析器AnnotationTransactionAttributeSource部分源码
        public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
        		implements Serializable {
        
        	private static final boolean jta12Present;
        
        	private static final boolean ejb3Present;
        
        	static {
        		ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
        		jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
        		ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
        	}
        
        	private final boolean publicMethodsOnly;
        
        	// 注解解析器集合
        	private final Set<TransactionAnnotationParser> annotationParsers;
        
        	...
        }
        

        属性解析器有一个成员变量是annotationParsers,可以添加多种注解解析器,重点关注Spring的注解解析器,部分源码如下:

        protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
        	RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        
        	Propagation propagation = attributes.getEnum("propagation");
        	rbta.setPropagationBehavior(propagation.value());
        	Isolation isolation = attributes.getEnum("isolation");
        	rbta.setIsolationLevel(isolation.value());
        	rbta.setTimeout(attributes.getNumber("timeout").intValue());
        	rbta.setReadOnly(attributes.getBoolean("readOnly"));
        	rbta.setQualifier(attributes.getString("value"));
        
        	List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
        	for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
        		rollbackRules.add(new RollbackRuleAttribute(rbRule));
        	}
        	for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
        		rollbackRules.add(new RollbackRuleAttribute(rbRule));
        	}
        	for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
        		rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
        	}
        	for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
        		rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
        	}
        	rbta.setRollbackRules(rollbackRules);
        
        	return rbta;
        }
        

        属性解析器的作用就是用来解析@Transaction注解

        • TransactionInterceptor 事务拦截器,部分源码如下
        // 构造方法传入
        public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
        	setTransactionManager(ptm);
        	setTransactionAttributeSource(tas);
        }
        
        
        @Override
        @Nullable
        public Object invoke(MethodInvocation invocation) throws Throwable {
        
        	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
        
        	// 添加事务支持
        	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
        }
        
      • 上述组件如何管理起来?

        • 事务拦截器实现MethodInterceptor接口,追溯一下上面提到的InfrastructureAdvisorAutoProxyCreator后置处理器,它会在代理对象执行目标方法时获取其拦截器链,而拦截器链就是TransactionInterceptor,这就把两个组件联系起来;
        • 构造方法传入PlatformTransactionManager(事务管理器)、TransactionAttributeSource(属性解析器),但是追溯一下上面的ProxyTransactionManagementConfiguration的源码,在注册事务拦截器的时候并没有调用这个带参构造函数,而是调用的无参构造方法,然后再调用set方法注入这两个属性,效果一样。
      • invokeWithinTransaction方法,部分源码如下

      protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      		final InvocationCallback invocation) throws Throwable {
      
      	// If the transaction attribute is null, the method is non-transactional.
      	// 获取属性解析器,即在ProxyTransactionManagementConfiguration容器配置类中注册事务拦截器时注入的
      	TransactionAttributeSource tas = getTransactionAttributeSource();
      	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
      	// 获取事务管理器
      	final PlatformTransactionManager tm = determineTransactionManager(txAttr);
      	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
      
      	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
      		// Standard transaction demarcation with getTransaction and commit/rollback calls.
      		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
      
      		Object retVal;
      		try {
      			// This is an around advice: Invoke the next interceptor in the chain.
      			// This will normally result in a target object being invoked.
      			retVal = invocation.proceedWithInvocation();
      		}
      		catch (Throwable ex) {
      			// target invocation exception
      			// 如果目标方法抛异常,会执行completeTransactionAfterThrowing(获取事务管理器,执行回滚操作)
      			completeTransactionAfterThrowing(txInfo, ex);
      			throw ex;
      		}
      		finally {
      			cleanupTransactionInfo(txInfo);
      		}
      		// 如果目标方法正常运行,则会执行commitTransactionAfterReturning(获取事务管理器,执行提交事务操作)
      		commitTransactionAfterReturning(txInfo);
      		return retVal;
      	}
      
      	...
      }
      
      • 过程:
      @EnableTransactionManagement 注解
      1)通过@Import引入TransactionManagementConfigurationSelector类
      			它的selectImports方法导入了另外两个类:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
      2)AutoProxyRegistrar类分析
      			方法registerBeanDefinitions中,引入其他类,通过AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)引⼊
      InfrastructureAdvisorAutoProxyCreator,它继承了AbstractAutoProxyCreator,是⼀个
      后置处理器类
      3)ProxyTransactionManagementConfiguration是一个添加了@Configuration注解的配置类
      		注册事务增强器(注入属性解析器、事务拦截器)
      			属性解析器:AnnotationTransactionAttributeSource,内部持有解析器集合Set annotationParsers;
      			具体使用的是SpringTransactionAnnotationParser解析器,用来解析@Transactional的事务属性
      			事务拦截器:TransactionInterceptor实现了MethodInterceptor接口,该通用拦截会在产生代理对象之前和aop增强合并,最终一起影响到代理对象
      			TransactionInterceptor的invoke方法中invokeWithinTransaction会触发原有业务逻辑调用(增强事务)
      

      你可能感兴趣的:(Spring,spring,java)