本篇文章为你整理了源码框架(源码框架脑图)的详细内容,包含有源码框架多少钱 源码框架脑图 源码框架下载 开源框架源码 源码框架,希望能帮助你了解 源码框架。
目录SpringIOC源码IOC容器加载过程及Bean生命周期BeanFactory和ApplicationContext的区别Spring IOC容器的具体加载过程简述Bean的生命周期后置处理器的九次调用内置后置PostProcess处理器BeanFactoryPostProcessor的调用过程/配置类的解析过程配置类@Configuration加与不加的区别重复beanName覆盖原则循环依赖如何解决循环依赖/为什么要有二级缓存和三级缓存Spring三级缓存解决setter方式的循环依赖原理BeanCurrentlyInCreationException监听器ListenerSpring事件监听器的原理Spring是怎样避免读取到不完整的Bean推断构造方法底层原理SpringAOP底层原理Spring事务Spring事务的7种传播行为1、PROPAGATION_REQUIRED2、PROPAGATION_SUPPORTS3、PROPAGATION_MANDATORY4、PROPAGATION_REQUIRES_NEW5、PROPAGATION_NOT_SUPPORTED6、PROPAGATION_NEVER7、PROPAGATION_NESTED8、总结用法Spring事务不生效Transaction rolled back because it has been marked as rollback-only切面类内的事务自定义AOP与声明式事务执行顺序问题
SpringIOC源码
Spring源码大纲 https://www.processon.com/view/link/5f5075c763768959e2d109df
IOC加载流程图 https://www.processon.com/view/link/5f15341b07912906d9ae8642
Spring循环依赖图 https://www.processon.com/view/link/5f1fb2cf1e08533a628a7b4c
Spring Xmind 小结
IOC容器加载过程及Bean生命周期
文中 spring-boot-dependencies 的 version 基于 2.3.6.RELEASE
spring-cloud-dependencies的 version 基于 Hoxton.SR3
BeanFactory和ApplicationContext的区别
Spring Framework 中文文档
BeanFactory和ApplicationContext的区别就是工厂和4S店的区别
BeanFactory是Bean的工厂,spring的顶层核心接口,没有BeanFactory就没有Bean的存在,工厂只负责按照要求生产Bean,Bean的定义信息,要生产成什么样由下家(ApplicationContext)说了算。
ApplicationContext面向的是用户,所以需要更好的服务用户,不仅要提供Bean和调用工厂去生产Bean还要提供一系列人性化的服务如国际化、加载Bean定义、监听器等等,怎么生成Bean的事交给工厂去做。
但是ApplicationContext也依赖工厂,没有工厂他没有办法提供Bean,没有办法更好的服务用户,所以它需要继承工厂;ApplicationContext 继承自 BeanFactory,但是它不应该被理解为 BeanFactory 的实现类,而是说其内部持有一个实例化的 BeanFactory(DefaultListableBeanFactory)。以后所有的 BeanFactory 相关的操作其实是给这个实例来处理的。DefaultListableBeanFactory也有注册bean定义的能力。
BeanDefinition是bean在spring中的描述,有了BeanDefinition我们就可以创建Bean。
BeanDefinition接口: 顶级基础接口封装了生产Bean的一切原料,用来描述Bean,里面存放Bean元数据,比如class表示Bean类型、scope表示bean作用域/是否为单例、属性、构造函数参数列表、依赖的bean、lazyInit表示是否是懒加载、bean初始销毁会调用的方法等信息。
Spring IOC容器的具体加载过程
spring的配置方式一般有三种:
1.注解配置
2.xml配置
3.JavaConfig配置
通过main函数创建 spring 高级容器有多种方式:
ClassPathXmlApplicationContext 基于classpath下的xml配置文件创建容器(少见)
FileSystemXmlApplicationContext 从磁盘路径查找 XML 配置文件创建容器(少见)
AnnotationConfigApplicationContext 基于纯注解开发、JavaConfig 配置文件
Spring Boot 根据WebApplicationType来推断选择哪个容器创建,WebApplicationType有以下3种类型:
NONE 非web环境下的启动容器,AnnotationConfigApplicationContext,比如 Spring Cloud 环境下容器通过 BootstrapApplicationListener 添加的id=bootstrap的Spring Boot子容器是这种类型的容器
SERVLET 基于 servlet 的 web 容器,XmlWebApplicationContext、AnnotationConfigWebApplicationContext或者AnnotationConfigServletWebServerApplicationContext,适用于普通的Spring Boot Web项目
REACTIVE 使用响应式的 web 容器, AnnotationConfigReactiveWebServerApplicationContext,在 Spring-Cloud-Gateway 中,基于REACTIVE 环境的启动容器是这种类型
AnnotationConfigApplicationContext 支持从给定的包路径和配置类启动容器,下文以它的构造函数来展开IOC容器的加载过程。
public AnnotationConfigApplicationContext(Class ? ... componentClasses) {
this(); // 1.准备工作
register(componentClasses); // 2.注册配置类
refresh(); // 3.IOC容器刷新
// 1. 这是一个有参的构造方法,可以接收多个配置类,不过一般情况下,只会传入一个配置类。
// 2. 这个配置类有两种情况,一种是传统意义上的带上@Configuration注解的配置类,还有一种是没有带上@Configuration,但是带有@Component,@Import,@ImportResouce,@Service, @ComponentScan等注解的配置类,在Spring内部把前者称为Full配置类,把后者称之为Lite配置类。
1.准备工作过程中,实例化了一些对象:bean工厂、reader、scanner(这3个是AnnotationConfigApplicationContext的成员变量)
父类构造函数 GenericApplicationContext 中为spring上下文,实例化了beanFactory:DefaultListableBeanFactory 。
DefaultListableBeanFactory 是最底层,实现功能最全的BeanFactory
AnnotationConfigApplicationContext#reader = new AnnotatedBeanDefinitionReader(this);
初始化注解模式下bean定义扫描器, 而且注册了很多的创世纪后置处理器,比如:
解析我们配置类的后置处理器ConfigurationClassPostProcessor(它实现了BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor接口,用来处理配置类解析@Configuration、@ComponentScan、@Import等);
AutowiredAnnotationBeanPostProcessor(BeanPostProcessor的实现,解析@Autowired);
AnnotationAwareOrderComparator(Order注解相关)等等。这些后置处理器诞生时间最早,有了它们之后才能有我们添加的普通bean,故名创世纪后置处理器。
AnnotationConfigApplicationContext#scanner = new ClassPathBeanDefinitionScanner(this);
初始化classPath类型bean定义扫描器,可以用来扫描指定包下所有类,并将符合过滤条件的类(设置this.includeFilters =AnnotationTypeFilter(Component.class))封装成 beanDefinition 注册到容器,适用于没有指定配置类时手动调用scan,不是默认的扫描包对象,可忽略
下面举例BeanDefinitionReader (Bean定义读取器)、BeanDefinitionScanner (Bean定义扫描器)的简单用法
package com.example.demo;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
public class Test {
/**
* @see AnnotatedBeanDefinitionReader
* 传入 BeanDefinitionRegistry 具有注册Bean定义到注册表的能力
* public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
* this(registry, getOrCreateEnvironment(registry));
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);
//将Teacher.class解析为BeanDefinition
reader.register(Teacher.class);
System.out.println(context.getBean("teacher"));
System.out.println(context.getBean("student"));
//打印结果
//com.example.demo.Teacher@2177849e
//com.example.demo.Student@40cb8df7
class Teacher {}
@Component
class Student {}
@ComponentScan("com.example.demo")
class AppConfig {
BeanDefinitionReader可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解,它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、 @Role、@Description。类上不需要@Component类似注解
package com.example.demo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.stereotype.Component;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.example.demo");
System.out.println(context.getBean("teacher"));
//打印结果
//com.example.demo.Teacher@7b02881e
@Component
class Teacher {}
ClassPathBeanDefinitionScanner也能将类解析为BeanDefinition,但它需要通过扫描某个包路径,对包路径下的类进行解析,类上有类似@Component 注解的类,才能解析为一个BeanDefinition
2.注册配置类
将配置类也添加到beanDefinitionMap中,在此之前beanDefinitionMap中只有上一步添加的几个创世纪后置处理器,在此之后beanDefinitionMap中就多了配置类这个beanDefinition。添加到beanDefinitionMap的逻辑看这个方法: DefaultListableBeanFactory#registerBeanDefinition
beanDefinitionMap是我们创建的bean工厂-DefaultListableBeanFactory的成员变量
3.IOC容器刷新过程-源码debug
AbstractApplicationContext#refresh()
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
Spring解析xml配置文件,将要创建的所有bean配置信息保存起来;JavaConfig下只刷新该beanFactory,包括 beanDefinitionMap和beanDefinitionNames等
invokeBeanFactoryPostProcessors(beanFactory)
执行BeanFactoryPostProcessor 调用BeanFactory的后置处理器,真正的扫描包对象scanner扫描class,解析成beanDefinition并注册到beanDefinitionMap
registerBeanPostProcessors(beanFactory)
注册Bean后置处理器
finishBeanFactoryInitialization(beanFactory)
实例化所有剩余的(非延迟初始化)单例
beanFactory.preInstantiateSingletons()
获取容器中所有bean定义的名称;
合并BeanDefinition生成RootBeanDefinition;
判断beanDefinition是不是抽象的 不是单例的 不是懒加载的;
判断是否FactoryBean是则创建,SmartFactoryBean调用工厂方法getobject返回内部对象,不是FactoryBean调用getBean();getBean( beanName)返回的是FactoryBean,beanDefinitionMap中只有FactoryBean,但单例池最终会生成2个bean
// 接下来是核心!!!getBean方法
AbstractBeanFactory#getBean调用#doGetBean
DefaultSingletonBeanRegistry#getSingleton(beanName) 为空,往下调用
DefaultSingletonBeanRegistry#getSingleton(beanName,singletonFactory) 钩子函数调用
AbstractAutowireCapableBeanFactory#createBean调用#doCreateBean,再依次调用
AbstractAutowireCapableBeanFactory#resolveBeanClass 加载类 先加载当前BeanDefinition所对应的class
AbstractAutowireCapableBeanFactory#createBeanInstance 实例化(addSingletonFactory放入缓存)
AbstractAutowireCapableBeanFactory#populateBean 属性注入,填充属性/注入依赖
AbstractAutowireCapableBeanFactory#initializeBean 初始化,执行aware接口中的方法,完成AOP代理,最后把最终生成的代理对象放入单例池,下次getBean时就直接从单例池拿即可
// AbstractAutowireCapableBeanFactory#createBeanInstance,在这一步,bean的实例化过程是:
// 使用合适的实例化策略来创建新的实例,包括用:工厂方法、构造函数自动注入、简单初始化
1.首先判断BeanDefinition中是否设置了Supplier,如果设置了则调用Supplier的get()得到对象。
2.如果没有设置Supplier,检查BeanDefinition中是否设置了factoryMethod,然后调用工厂方法得到对象。配置类中@Bean注解所标记的方法就是factoryMethod,配置类对应为factoryBean。
3.推断构造方法:根据class推断构造方法,根据推断出来的构造方法,反射得到一个对象。
// DefaultSingletonBeanRegistry#getSingleton(beanName)
一级缓存二级缓存beanName不存在且标记为正在创建,加锁,取出三级缓存的Bean工厂调用getObject方法拿到单例对象或代理对象,将单例对象添加到二级缓存中,移除三级缓存单例工厂中对应的singletonFactory
// AbstractAutowireCapableBeanFactory#addSingletonFactory放入三级缓存
InstantiationAwareBeanPostProcessor#postProcessAfterInitialization是后置处理器的扩展点,允许在对象返回之前修改甚至替换bean;
如果存在AOP,返回的不是原始的Bean实例,而是实现AOP方法的代理类;
只用二级缓存会将AOP中创建代理对象的时机提前,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理;
循环依赖发生时提前代理,没有循环依赖代理方式不变,依然是初始化以后代理;
有ab对象,getBean(a)在加载b的流程中如果发生了循环依赖,就是说b又依赖了a,我们就要对a执行AOP,
提前获取增强以后的a对象,这样b对象依赖的a对象就是增强以后的a了。
见https://segmentfault.com/a/1190000023712597
简述Bean的生命周期
1.利用该类的构造方法来实例化得到一个对象(但是如何一个类中有多个构造方法,Spring则会进行选择,这个叫做推断构造方法)
2.得到一个对象后,Spring会判断该对象中是否存在被@Autowired注解了的属性,把这些属性找出来并由Spring进行赋值(依赖注入)
3.依赖注入后,Spring会判断该对象是否实现了BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口,如果实现了,就表示当前对象必须实现该接口中所定义的setBeanName()、setBeanClassLoader()、setBeanFactory()方法,那Spring就会调用这些方法并传入相应的参数(Aware回调)
4.Aware回调后,Spring会判断该对象中是否存在某个方法被@PostConstruct注解了,如果存在,Spring会调用当前对象的此方法(初始化前)
5.紧接着,Spring会判断该对象是否实现了InitializingBean接口,如果实现了,就表示当前对象必须实现该接口中的afterPropertiesSet()方法,那Spring就会调用当前对象中的afterPropertiesSet()方法(初始化)
6.最后,Spring会判断当前对象需不需要进行AOP,如果不需要那么Bean就创建完了,如果需要进行AOP,则会进行动态代理并生成一个代理对象做为Bean(初始化后)
后置处理器的九次调用
Instantiation AwareBeanPostProcessor
AnnotationAwareAspectJAutoProxyCreator解析aop切面信息进行缓存
SmartInstantiation AwareBeanPostProcessor
通过bean的后置处理器进行选举出合适的构造函数对象
InstantiationAware BeanPostProcessor
可以修改填充属性的值 处理@AutoWired
BeanFactoryPostProcessor的调用过程/配置类的解析过程
https://www.processon.com/view/link/5f18298a7d9c0835d38a57c0
调用bean工厂的后置处理器
1)BeanDefinitionRegistryPostProcessor(先被执行) 它是能注册BeanDefinition 的子接口
所有的bean定义信息将要被加载到容器中,Bean实例还没有被初始化
2)BeanFactoryPostProcessor(后执行) 它是修改BeanDefinition 但不能注册BeanDefinition 的父接口
所有的Bean定义信息已经加载到容器中,但是Bean实例还没有被初始化
在这里可以修改BeanDefinition 即通过设置bean对象的类型 setBeanClassName 进行偷天换日
1.去容器中获取BeanDefinitionRegistryPostProcessor的bean的处理器名称
// 判断是否实现了PriorityOrdered接口的,getBean,调用他的后置处理方法
2.去容器中获取BeanDefinitionRegistryPostProcessor的bean的处理器名称
// 判断是否实现了Ordered接口的,getBean,调用他的后置处理方法
3.去容器中获取BeanDefinitionRegistryPostProcessor的bean的处理器名称
// 剩下的没有被处理过的,getBean,调用他的后置处理方法
4.去容器中获取BeanDefinitionRegistryPostProcessor,同时实现了BeanFactoryPostProcessor的bean的处理器名称
// getBean 调用他的后置处理方法
123后置处理方法 #postProcessBeanDefinitionRegistry
4后置处理方法 #postProcessBeanFactory
// ConfigurationAnnotationProcessor 会走第一步、第四步
5.获取容器中所有的 BeanFactoryPostProcessor
6.先调用BeanFactoryPostProcessor实现了 PriorityOrdered接口的
7.再调用BeanFactoryPostProcessor实现了 Ordered的
8.调用没有实现任何方法接口的 后置处理方法 BeanFactoryPostProcessor#postProcessBeanFactory
拓展点:
其他框架基于spring的后置处理器这一拓展点,整合了自己的技术,这点我们也可以学习借鉴。
BeanFactoryPostProcessor 修改BeanDefinition
BeanDefinitionRegistryPostProcessor 注册BeanDefinition eg:集成Mybatis,根据mapper接口创建代理对象(源码看MapperScannerConfigurer);dubbo类似。
BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 做了什么?
循环bean定义名称names找到配置类,判断其是完全的配置类还是一个非正式的配置类;
创建一个配置类解析器对象真正地解析配置类,parser.parse(),把我们扫描出来的类添加到beanDefinition的集合即beanDefinitionMap(@ComponentScan);
新建一个ConfigurationClassBeanDefinitionReader,把我们解析出来的配置类configClasses(解析出来的配置类)注册到容器中(@Import、@Bean、@ImportResources、ImportBeanDefinition注解)
自定义beanFactory后置处理器会在第一步1.被ConfigurationClassPostProcessor扫描添加到 beanFactory 的BeanDefinitionMap,在第三步3.时被getBean,再调用自定义beanFactory后置处理器的后置处理方法;如果是在配置类里通过@Bean方式注册自定义beanFactory后置处理器,会getBean(自定义beanFactory后置处理器)- getBean(配置类),导致配置类提前生成。配置类增强失败。(以下方式一)
解决:static关键字修饰@Bean方法返回为BeanPostProcessor、BeanFactoryPostProcessor等类型的方法
// 方式1:
package com.example.demo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
public class Test {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(AppConfig.class);
@Configuration
@ComponentScan("com.example.demo")
class AppConfig {
AppConfig() { System.out.println("AppConfig init...");}
@Bean
BeanDefinitionRegistryPostProcessor postProcessor() {return new MyBeanDefinitionRegistryPostProcessor();}
class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
MyBeanDefinitionRegistryPostProcessor() {System.out.println("MyBeanDefinitionRegistryPostProcessor init...");}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
// 控制台输出
AppConfig init...
MyBeanDefinitionRegistryPostProcessor init...
// 警告
org.springframework.context.annotation.ConfigurationClassPostProcessor enhanceConfigurationClasses
Cannot enhance @Configuration bean definition appConfig since
its singleton instance has been created too early.
The typical cause is a non-static @Bean method
with a BeanDefinitionRegistryPostProcessor return type:
Consider declaring such methods as static.
// 方式2: 加上static修改postProcessor方法
// 控制台输出日志与方式一不同
MyBeanDefinitionRegistryPostProcessor init...
AppConfig init...
配置类@Configuration加与不加的区别
配置类加@Configuration的话,@Bean里方法名获取对象,对象只实例化一次
在BeanDefinitionRegistryPostProcessor中第4步4.调用postProcessBeanFactory方法时给配置类创建cglib动态代理,指定配置时不加Configuration也行,但加了@Configuration会根据方法名从单例池拿getBean,这样就有bean和bean之间的引用,而不是重复加载bean
@Configuration为Full配置类,经过enhance增强,所有的@Bean方法都被BeanMethodInterceptor拦截
重复beanName覆盖原则
loadBeanDefinitionsForBeanMethod
1、配置类的名字相同,则报错(同名@Component)
2、同一个配置类中的@Bean名字相同,则返回true,意思是以先加载的@Bean方法为准
3、不同的配置类中的@Bean名字相同,则返回false,意思是可以被覆盖,已后被加载的@Bean方法为准
如何解决循环依赖/为什么要有二级缓存和三级缓存
https://note.youdao.com/ynoteshare/index.html?id=01ec86d7955e2c9cd45c1c0e22f07535 type=note _time=1635692387674
三级缓存结构
Map String,Object singletonObjects // 一级缓存
Map String,Object earlySingletonObjects // 二级缓存
Map String,ObjectFactory singletonFactories // 三级缓存
一级缓存的作用:存放可用的成品bean;
二级缓存的作用:为了将成熟Bean和纯净Bean分离(未注入属性),避免多线程下读取到不完整的Bean;存放半成品bean,半成品bean即已经调用完构造但是还没有注入属性和初始化;
三级缓存的作用:用来生产半成品的bean,与getbean方法解耦,能解决aop增强下的循环依赖;存放函数接口/钩子函数,函数接口实现创建动态代理调用BeanPostProcessor,即其要加强的aop处理(为了避免重复创建,调用会返回动态代理对象或者原实例,再存储在二级缓存);
真正的解决循环依赖是靠二级缓存,不用三级缓存也可以解决循环依赖,但这样就造成了在实例化后就立马完成代理,违背了最后一步完成代理的原则;
在创建bean的时候,在哪里通过什么方式创建了动态代理:通过BeanPostProcessor创建动态代理,在初始化之后或在出现循环依赖时实例化之后(实例化 - 属性注入 - 初始化)
发生循环依赖会用到二级缓存,普通依赖过程只用到一三级缓存
Spring三级缓存解决setter方式的循环依赖原理
为什么Spring不能解决构造器的循环依赖?
从流程图应该不难看出来,在Bean调用构造器实例化之前,一二三级缓存并没有Bean的任何相关信息,在实例化之后才放入三级缓存中,因此当getBean的时候缓存并没有命中,这样就抛出了循环依赖的异常了。
为什么多例Bean不能解决循环依赖?
我们的bean是单例的,而且是字段注入(setter注入)的,单例意味着只需要创建一次对象,后面就可以从缓存中取出来,字段注入,意味着我们无需调用构造方法进行注入。
如果是原型bean,那么就意味着每次都要去创建对象,无法利用缓存;
如果是构造方法注入,那么就意味着需要调用构造方法注入,也无法利用缓存。
如何进行拓展?
bean可以通过实现SmartInstantiationAwareBeanPostProcessor接口getEarlyBeanReference方法进行拓展
BeanCurrentlyInCreationException
spring的aop代理(包括@Aysnc,@Transactional),一般都是在属性赋值时中调用#postProcessAfterInitialization方法创建的代理对象,这个代理过程是不涉及到循环引用的情况下执行;在循环引用下会提前创建代理对象#getEarlyBeanReference(ab循环依赖,a通过ObjectFactory提前曝光自己,b通过getObject获取到这个提前曝光的a对象填充属性,该earlySingletonReference放进二级缓存,只有循环依赖下才会放入二级缓存),
如果循环引用下提前创建了代理对象,经过initializeBean初始化又产生代理对象(exposedObject与earlySingletonReference两者不等抛BeanCurrentlyInCreationException异常,@Aysnc会发生,@Transactional不会发生);解决方式:加上@lazy
spring循环依赖在 构造器注入下会抛异常BeanCurrentlyInCreationException 可以用基于属性注入
监听器Listener
Spring事件体系包括三个组件:事件,事件监听器,事件广播器。基于观察者模式。
事件(ApplicationEvent)负责对应相应监听器,事件源发生某事件是特定事件监听器被触发的原因。事件分为 Spring内置事件 、自定义事件(继承ApplicationEvent)
事件监听器(ApplicationListener)对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。 分为 基于接口(继承ApplicationListener)、基于注解 (@EventListener)
事件广播器(ApplicationEventMulticaster)对应于观察者模式中的被观察者/主题, 负责通知观察者对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器。
发布者调用applicationContext.publishEvent(msg),将事件发送给了EventMultiCaster,而后由 EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。
Spring事件监听器的原理
IOC容器刷新接口refresh方法
initApplicationEventMulticaster 创建事件多播器(默认的事件广播器SimpleApplicationEventMulticaster)
registerListeners 把我们的事件监听器名字注册到多播器上,通过多播器进行播发早期事件
finishRefresh 容器刷新,发布刷新事件(ContextRefreshedEvent)
Spring提供的事件机制默认是同步的(SimpleApplicationEventMulticaster#multicastEvent),如果想用异步的可以自己实现ApplicationEventMulticaster接口,并在Spring容器中注册id为applicationEventMulticaster的Bean
Spring是怎样避免读取到不完整的Bean
防止多线程下Spring读取到不完整Bean加了两把锁
一把锁放在getSingleton()方法三级缓存,第二个线程阻塞直到第一个线程把二三级缓存删除完;
一把锁放在getSingleton(,)方法,先从单例池再拿一遍单例对象(double check防重复创建单例bean)
怎么样可以在所有Bean创建完后做扩展代码?
ContextRefreshedEvent/SmartInitializingSingleton
推断构造方法底层原理
Spring的判断逻辑如下:
1.如果一个类只存在一个构造方法,不管该构造方法是无参构造方法,还是有参构造方法,Spring都会用这个构造方法
2.如果一个类存在多个构造方法
a.这些构造方法中,存在一个无参的构造方法,那么Spring就会用这个无参的构造方法
b.这些构造方法中,不存在一个无参的构造方法,那么Spring就会报错
c.如果某个构造方法上加了@Autowired注解,Spring就会用这个加了@Autowired注解构造方法了
SpringAOP底层原理
https://www.processon.com/view/link/5faa4ccce0b34d7a1aa2a9a5
Bean的生命周期 : UserService.class - 无参构造方法(推断构造方法)- 普通对象 - 依赖注入(属性赋值) - 初始化前 - 初始化 - 初始化后 - 代理对象(UserServiceProxy) - Bean
1.找出所有的切面Bean
2.遍历切面中的每个方法,看是否写了@Before、@After等注解
3.如果写了,则判断所对应的Pointcut是否和当前Bean对象的类是否匹配
4.如果匹配则表示当前Bean对象有匹配的的Pointcut,表示需要进行AOP
利用cglib进行AOP的大致流程:
1.生成代理类UserServiceProxy,代理类继承UserService
2.代理类中重写了父类的方法,比如UserService中的test()方法
3.代理对象持有普通对象的引用,UserServiceProxy.target = 普通对象
4.调用代理类的test方法 - 先执行切面逻辑@Before,再执行target.test方法
target指定需增强的实现类;
interceptorNames 指定Advice(MethodBeforeAdvice, AfterReturningAdvice)、Interceptor(MethodInterceptor)、Advisor(结合Advice或Interceptor)都行;
Advice、Interceptor拦截器的粒度只控制到了类级别,类中所有的方法都进行拦截;Advisor拦截器的粒度达到方法级别,通知者切点分为正则匹配/方法名;需要获取这个代理类
2.autoProxy方式: 根据advisor批量创建自动代理(当Spring发现一个bean需要被切面织入的时候,Spring会自动生成这个bean的一个代理来拦截方法的执行,确保定义的切面能被执行);不需要获取这个代理类
BeanPostProcessor手动指定Advice方式,BeanNameAutoProxyCreator指定Advisor,可以使用正则来匹配要创建代理的那些Bean的名字
BeanPostProcessor自动扫描Advisor方式,DefaultAdvisorAutoProxyCreator
1.配置类,加入@EnableAspectJAutoProxy注解
2.切面类,加入@Aspect注解,定义一个Pointcut方法(切点:指定哪些类需要被代理),最后定义一系列的增强方法(Advice通知:代理逻辑)
切面类的解析: AspectJAutoProxyRegistrar实现ImportBeanDefinitionRegistrar,在解析配置类到容器时,如果开启@EnableAspectJAutoProxy注解下,通过registerBeanDefinitions方法为我们容器导入beanDefinition;该beanDefinition 是 AnnotationAwareAspectJAutoProxyCreator,继承自AbstractAutoProxyCreator,#findCandidateAdvisors在bean实例化前解析aop切面信息,生成对应的Advisor对象进行缓存
AbstractAdvisorAutoProxyCreator非常强大以及重要,只要Spring容器中存在这个类型的Bean,就相当于开启了AOP,AbstractAdvisorAutoProxyCreator实际上就是一个BeanPostProcessor,所以在创建某个Bean时,就会进入到它对应的生命周期方法中,比如:在某个Bean初始化之后,会调用wrapIfNecessary()方法进行AOP,底层逻辑是AbstractAdvisorAutoProxyCreator #getAdvicesAndAdvisorsForBean 会找到所有的通知器Advisor,然后判断当前这个Bean是否存在某个Advisor与之匹配(根据Pointcut)AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply ,如果匹配就表示当前这个Bean有对应的切面逻辑,需要进行AOP,需要产生一个代理对象。
// ProxyFactory产生代理对象
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(new PointcutAdvisor() {
@Override
public Pointcut getPointcut() {
return new StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class ? targetClass) {
return method.getName().equals("test");
@Override
public Advice getAdvice() {
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
@Override
public boolean isPerInstance() {
return false;
UserInterface userService = (UserInterface) proxyFactory.getProxy();
userService.test();
代理对象执行过程: CglibAopProxy.DynamicAdvisedInterceptor#intercept
1.在使用ProxyFactory创建代理对象之前,需要往ProxyFactory先添加Advisor
2.代理对象在执行某个方法时,会把ProxyFactory中的Advisor拿出来和当前正在执行的方法进行匹配筛选
3.把和方法所匹配的Advisor适配成MethodInterceptor
4.把和当前方法匹配的MethodInterceptor链,以及被代理对象、代理对象、代理类、当前Method对象、方法参数封装为MethodInvocation对象
5.调用MethodInvocation的proceed()方法,开始执行各个MethodInterceptor以及被代理对象的对应方法
6.按顺序调用每个MethodInterceptor的invoke()方法,并且会把MethodInvocation对象传入invoke()方法
7.直到执行完最后一个MethodInterceptor了,就会调用invokeJoinpoint()方法,从而执行被代理对象的当前方法
Spring事务
当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。
事务注解@EnableTransactionManagement 为我们的容器导入了添加了两个Bean:
AutoProxyRegistrar 导入的 InfrastructureAdvisorAutoProxyCreator :开启自动代理
ProxyTransactionManagementConfiguration 导入的 BeanFactoryTransactionAttributeSourceAdvisor(Advisor)、AnnotationTransactionAttributeSource(pointcut)、TransactionInterceptor(advice)
事务是基于AOP完成的,判断bean生命周期是否开启aop:找到所有的通知器对象Advisor,判断这个bean是否与Advisor匹配:通过pointcut对象(解析@Transactional注解,匹配逻辑为判断该Bean的类上是否存在@Transactional注解,或者类中的某个方法上是否存在@Transactional注解)、Advice对象(TransactionalInterceptor 代理的逻辑)
该代理对象在执行某个方法时,会再次判断当前执行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配则执行该Advisor中的TransactionInterceptor的invoke()方法,执行基本流程为:
Spring事务的代理对象执行某个方法时的步骤:
1.判断当前执行的方法是否存在@Transactional注解
2.如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
3.修改数据库连接的autocommit为false,数据库连接放入threadlocal
4.执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
5.执行完了之后如果没有出现异常,则提交,否则回滚
Spring事务的7种传播行为
https://blog.csdn.net/weixin_39625809/article/details/80707695
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。
1、PROPAGATION_REQUIRED
如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA(){}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB(){}
单独调用A、B方法都会开启一个新的事务
A调用B方法、B调用A方法都会加入到同一个事务
2、PROPAGATION_SUPPORTS
如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA(){}
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB(){}
单独调用B方法不会开启事务
A调用B方法,B会加入这个事务
3、PROPAGATION_MANDATORY
如果存在一个事务,支持当前事务。如果没有事务,则抛出异常。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA(){}
@Transactional(propagation = Propagation.MANDATORY)
public void methodB(){}
单独调用B方法会抛IllegalTransactionStateException异常
A调用B方法,B会加入这个事务
4、PROPAGATION_REQUIRES_NEW
如果存在一个事务,先将这个存在的事务挂起,再开启一个新的事务。如果没有事务则开启一个新的事务。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA(){}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB(){}
单独调用B方法开启事务
A方法(外层事务)调用B方法(内层事务),B会开启一个新的事务
外层事务回滚,内层事务仍然提交
5、PROPAGATION_NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务。
6、PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常。
7、PROPAGATION_NESTED
如果存在一个事务,依赖该事务,作为该事务的子事务。如果没有事务则开启一个新的事务。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA(){}
@Transactional(propagation = Propagation.NESTED)
public void methodB(){}
单独调用B方法开启事务
A方法(外层事务)调用B方法(内层事务),nested属于子事务,依赖于外层,有单独的保存节点
外层事务的回滚可以引起内层事务的回滚,内层事务异常的回滚可导致外层事务的回滚(如果没有吞掉异常)
也可不导致外层事务的回滚(吞掉异常),外层事务自行决定是commit还是rollback
case1:如果A捕获B的异常,并且未向上抛异常
case2:如果A未捕获B的异常,则默认将B的异常向上抛
REQUIRES_NEW和NESTED:内层事务抛异常一定会回滚,外层事务可以通过控制吞不吞内层事务抛的异常来决定是否回滚
case1:均回滚抛异常 case2:均回滚
case1:A正常提交B回滚 case2:均回滚
case1:A正常提交B回滚 case2:均回滚
@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP的本质决定的。如果你在 protected、private或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。
默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。
@Transactional不做任何配置,默认是对抛出的unchecked异常、Error回滚,checked异常不会回滚,为了让所有异常都会让事务启动可以将 @Transactional配置为 @Transactional(rollbackFor = Exception.class)
Spring事务不生效
框架不支持:入口的方法必须是public、事务是否在同一个线程里、数据库引擎设置不对数据库不支持事务
错误使用:只对出现运行期异常(java.lang.RuntimeException及其子类)/Error进行回滚、rollbackFor属性设置错误、异常被catch、错误地传播机制
代理失效:被final、static关键字修饰的类或方法、将注解标注在接口方法上将无法用CGLIB代理、是否通过代理对象只有代理对象调用方法才能被拦截
@Transactional(propagation = Propagation.REQUIRED)
public void methodA(){}
public void methodB(){}
A方法(事务)调用B方法(没有事务),B方法的异常也会导致AB方法事务的回滚
B方法(没有事务)调用A方法(事务),事务失效
Transaction rolled back because it has been marked as rollback-only
Spring的@Transactional 可以注解到方法上或者类上从而开启事务,而正确调用类事务方法是通过容器调用,即@autowird 被注入到其他类中使用,因为此时调用方法会被spring容器的 TransactionInterceptor 拦截器拦截
@Transactional(propagation = Propagation.REQUIRED)
public void methodA(){}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB(){}
Propagation.REQUIRED实例,默认事务实例不管是否捕获异常,全部一起回滚
A方法(外层事务)调用B方法(内层事务),B方法发现异常了会标记整个事务为roll-back
但如果外层方法捕获异常正常退出后执行commit事务,此时发现已经标记异常会出错抛UnexpectedRollbackException
部分失败。全局回滚属性为true
解决办法:在catch块中添加TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 手动回滚
或者内层事务使用propagation = Propagation.NESTED,从而保证内层异常不会影响外层提交
切面类内的事务
含有@Aspect的类在生命周期的第一个bean后置处理器会被标记不处理,在最后一个bean后置处理器它就不会被代理,故aop切面类本身使用不了声明式事务@Transactional;可以在切面类新写子方法新建事务,或用publisher.publishEvent发布异步事件新建事务
// 判断当前事务是否是新事务
TransactionAspectSupport.currentTransactionStatus().isNewTransaction()
// @Order
默认为@Order(value = Ordered.LOWEST_PRECEDENCE)优先度最低;可以自定义修改切面类的优先级别@Order(value = Ordered.HIGHEST_PRECEDENCE + 1)
自定义AOP与声明式事务执行顺序问题
@SysLog: 自定义AOP,产生系统日志
@Transactional:声明式事务
//某个service方法
@SysLog("/testService")
@Transactional(propagation = Propagation.REQUIRED)
public Result testService(Info info) {}
//自定义aop
@Aspect
@Component
public class SysLogAspect{
@Around("@annotation(sysLog)")
public Object around(ProceedingJoinPoint point, SysLog sysLog) {
obj = point.proceed();
innerService.do();
@Transactional(propagation = Propagation.REQUIRED)
public Result innerService(Info info) {}
在controller同时标记@SysLog和@Transactional时候,由于事务注解默认 @EnableTransactionManagement(order=Ordered.LOWEST_PRECEDENCE) 优先级最。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。