spring 原理

435 阅读22分钟

spring 中特别好用的反射类:org.springframework.util.ReflectionUtils

概览

(1)、控制反转(Inversion of Control,简称IoC)是Spring框架最核心的设计思想之一,其本质是将​​对象的创建、依赖管理和生命周期控制权从代码转移给容器​​(在Spring中即IoC容器)。这种"权力反转"带来了显著优势 **推动架构符合"依赖倒置原则";

  • 高层模块不应依赖低层模块,二者都依赖抽象。
  • 抽象不应依赖细节,细节应依赖抽象。

好处 1、类之间松耦合,,提高可测试性 2、提高对象复用,对象的创建、初始化、销毁逻辑由容器统一管理.

(2)、Aop 日志、事务、安全、性能监控等逻辑往往散落在多个业务模块中,将这些跨领域的功能从业务逻辑中剥离出来,封装成独立的模块。

优点: 减少代码量,提升可维护性,业务代码纯净,功能集中管理

(3)生态繁荣,企业级服务集成 Spring 通过抽象层和适配器模式无缝集成企业级技术栈,开发者无需关注底层差异。如mq集成,redis集成,数据库集成。衍生出 Spring Boot(简化配置和部署)、Spring Cloud(微服务)、Spring Security(安全)、Spring Data(数据访问简化)、Spring Batch(批处理)、Spring Integration(企业集成模式)等一系列功能强大的项目,几乎覆盖了企业级开发的方方面面。

(4)简化开发 减少样板代码,如果注解事务,访问jdbc等

原理

  • Spring 的启动流程:

image.png

ConfigurationClassPostProcessor

  • BeanFactoryPostProcessor>ConfigurationClassPostProcessor

注册ConfigurationClassPostProcessor

  • 什么时候注册ConfigurationClassPostProcessor到容器: spring boot 执行->prepareContext() > load()-->loader=createBeanDefinitionLoader---》AnnotatedBeanDefinitionReader-》registerAnnotationConfigProcessors();

这个地方总共注册了5个: org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory

loader.load(),接下来会把启动类加到容器里。

postProcessBeanDefinitionRegistry

扫整个包

  • //从容器里拿到所有的BeanDefinitionNames;String[] candidateNames = registry.getBeanDefinitionNames();

  • 因为这里只处理@Configuration注解的类checkConfigurationClassCandidate

  • @SpringBootApplication有这个注解 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)),开始处理这个类;

然后走parse逻辑

  • postProcessBeanDefinitionRegistry—

  • ConfigurationClassParser.parse---》

  • processConfigurationClass(shouldSkip)走条件注册Conditional—》doProcessConfigurationClass->

  • 1、@Component-> processMemberClasses(内部类)—》//递归处理candidateIndicators[Component,ComponentScan,Import,importResorce]--》processConfigurationClass ---》递归处理bean

为什么要递归处理,Component本身也可以当配置类,Component+bean lite模式
  • 2、@ PropertySources>processPropertySource【解析PropertySources属性值】如果有类上放有PropertySources ,则加载配置文件里的配置(createPropertySource)加入到envirenment里的PropertySources[ResourcePropertySource]里 (等AutowiredAnnotationBeanPostProcessor会用)

  • 3、@ ComponentScans/@ComponentScan—》ComponentScanAnnotationParser .parse----》 new ClassPathBeanDefinitionScanner()---》new这个对象的时候registerDefaultFilters—》includeFilters(@Component)一顿解析component参数,默认加载启动类所在的包] -->doScan> findCandidateComponents> scanCandidateComponents>扫描出来candidates>生成beanName> processCommonDefinitionAnnotations[设置Lazy, Primary, Role, Description, DependsOn]> applyScopedProxyMode创建代理beanDefination---注册bean容器》 //这一步只会通过@ComponentScan注解扫描的类才会加入到BeanDefinitionMap中

// 通过其他注解(例如@Import、@Bean)的方式,在parse()方法这一步并不会将其解析为BeanDefinition,而是先解析成ConfigurationClass类

// 真正放入到map中是在下面的this.reader.loadBeanDefinitions()方法中实现的

  • 4、 @ processImports和@ ImportResource 不常用

  • 5、 @Bean,处理Bean格式的bean

this.reader.loadBeanDefinitions(configClasses);
  • // 因此需要执行一次loadBeanDefinition(),这样就会执行ImportBeanDefinitionRegistrar或者ImportSelector接口的方法或者@Bean注释的方法 ->loadBeanDefinitionsForConfigurationClass registerBeanDefinitionForImportedConfigurationClass(configClass); loadBeanDefinitionsForBeanMethod(beanMethod); loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); 加载所有配置bean的bean定义
postProcessBeanFactory
  • 创建cglib动态代理类:

  • enhanceConfigurationClasses(beanFactory);

  • @Configuration+@bean full模式

  • @Component +@bean lite 模式

  • Full 模式下,会给配置类生成一个动态代理类,配置类中的所有方法都将被动态代理,因此配置类中的方法不能是 final 或者 private 的。

  • Full 模式下,一个 @Bean 方法调用另外一个 @Bean 方法,动态代理方法会先去容器中检查是否存在该 Bean,如果存在,则直接使用容器中的 Bean,否则才会去创建新的对象。

  • Lite 模式下,配置类中的方法就是普通方法,可以是 final 类型,也可以是 private。

  • Lite 模式下,不需要通过 CGLIB 生成动态代理类,所以启动速度会快一些。

  • Lite 模式下,一个 @Bean 方法调用另外一个 @Bean 方法,会导致同一个 Bean 被初始化两次。

spring envirentment

  • MutablePropertySources

系统变量,环境变量

  • org.springframework.core.env.StandardEnvironment#customizePropertySources[实例化环境的时候StandardEnvironment],

应用配置文件 application.properties

  • prepareEnvironment---》ConfigFileApplicationListener.load;监听
@PropertySources 注解标识的文件最低,ConfigurationClassPostProcessor加载

获取变量覆盖的时候按放入顺序的优先级

  • PropertySourcesPropertyResolver → AbstractPropertyResolver.getProperty();
  • JVM系统属性--》系统环境变量————》application文件--》@PropertySources注解的文件

ConfigurationPropertiesBindingPostProcessor

  • 1、什么时候注入使用注解@EnableConfigurationProperties引导类
  • 2、postProcessBeforeInitialization 进行属性绑定;

@Autowired 与@Resource

  • 区别: @Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false。支持 属性,setter, 构造器注入。

  • 如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用

  • @Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性或者当找不到与名称匹配的bean时才按照类型进行装配。只指出属性和setter注入,不支持构造器注入。

AutowiredAnnotationBeanPostProcessor
  • 什么时候加入容器:

  • 构造函数里已经加入了autowiredAnnotationTypes.add(Autowired.class,value.class);

  • 一、MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition

  • 查找bean的@Autowired @Value属性方法并缓存起来:

  • 遍历当前bean中的所有属性和方法,过滤静态属性和方法

  • 属性:将field、required封装成InjectedElement(AutowiredFieldElement,AutowiredMethodElement)

  • 方法:InjectionMetadata

  • 二、InstantiationAwareBeanPostProcessor#postProcessProperties

  • 给属性或者方法反射注册值。 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject

源码:Inject>--》doResolveDependency--》

value 注解

——> getSuggestedValue(找到有value注解的)> resolveEmbeddedValue >PlaceholderResolvingStringValueResolver#resolveStringValue > this::getPropertyAsRawString—>解析注入遍历propoties)--》

(autoware注解

——>findAutowireCandidates 按类型找到对应的beanName---> QualifierAnnotationAutowireCandidateResolver(isAutowireCandidate)-》org.springframework.beans.factory.support.DefaultListableBeanFactory#determineAutowireCandidate 【多个话 看是否有@Primary ———>@Priority按优先级——>按名字装配】->在判断是不是bean的时候使用。> resolveCandidate> beanFactory.getBean;

  • 3、 CommonAnnotationBeanPostProcessor

  • findResourceMetadata—>buildResourceMetadata—->metadata.inject—>—>element.inject—>getResourceToInject

  • —>getResource—>resolveBeanByName 按名字查找。

AOP实现

  • AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

  • (1)AspectJ 是 Java 生态中最成熟的 面向切面编程(AOP) 框架,其核心原理是通过 字节码增强 在编译期、类加载期或运行时动态植入切面逻辑。

image.png

  • (2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

  • 静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

  • Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

JDK代理

image.png

  • JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler生成动态创建一个符合某一接口的的实例。spring也是要生成代理类的,只不过通过反射执行目标方法。利用jdk内部的proxygenerator。相比cglib的asm,他是专用生成代理类的,通用性较弱。
实现了某个接口的方法才能被拦截,没有实现某个接口的方法,不会被拦截。
  • CGLIB(Code Generation Library),是一个代码生成的类库,可以在ASM方式运行时动态的生成指定类的一个子类对象,并覆盖父类方法,添加增强代码。CGLib 为每个代理方法生成一个 MethodProxy 对象,内部包含:FastClass 索引:为目标类和代理类各生成一个 FastClass,通过索引直接定位方法地址调用,跳过虚拟方法表查找。所以比反射优化还快。接近supper,那为什么不用supper,因为supper是静态绑定

CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。Final 修饰的方法也不会被代理,访问这个方法的时候访问的是父类的方法类似super.父类方法。

image.png

生成的子类大概如下
public class YourService$$EnhancerBySpringCGLIB$$0 extends YourService {
    private MethodInterceptor interceptor; // Spring注入的拦截器

    @Override
    public void doSomething() {
        // 1. 创建方法调用链
        MethodInvocation invocation = new CglibMethodInvocation(
            target,                     // 原始目标对象(父类实例)
            method,                     // 目标方法(doSomething)
            args,                       // 方法参数
            interceptorChain            // 包含所有切面的通知链
        );

        // 2. 执行拦截器链(按顺序触发切面逻辑)
        invocation.proceed();
    }
}
  • 源码分析:
 Advisor:{

     Pointcut--》要拦截的方法,切点

     Advice--->Interceptor 要执行的方法

    }
  • 注入实际:@EnableAspectJAutoProxy 注入 AnnotationAwareAspectJAutoProxyCreator

  • 创建代理有两个时机

  • 1、 在创建bean的时候,循环依赖,创建代理的bean。org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference

  • 2、 postProcessAfterInitialization 在初始化之后

Spring 的代理选择策略是 “优先 JDK 动态代理,必要时降级到 CGLib”。

postProcessAfterInstantiation 扫描注解
  • postProcessBeforeInstantiation(AbstractAutoProxyCreator)—》shouldSkip (AspectJAwareAdvisorAutoProxyCreator子类的)--》findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator子类)--》(super.findCandidateAdvisors(), 父类根据bean类型找到Advisor)--》 buildAspectJAdvisors---》 advisorFactory.isAspect ,拿到容器里的所有bean找到被标注了@apect的注解创建Advisor;

  • findCandidateAdvisors 找到org.springframework.aop.Advisor

  • 1 List advisors = super.findCandidateAdvisors(); 找到实现Advisor的bean

  • 2 aspectJAdvisorsBuilder.buildAspectJAdvisors() 找到打了@aspect注解的bean

postProcessAfterInitialization
  • postProcessAfterInitialization—》看看当前的bean满足不满足拦截的条件,如果满足就创建代理bean。wrapIfNecessary-> getAdvicesAndAdvisorsForBean > createProxy> proxyFactory.getProxy—》createAopProxy().getProxy—》JDK/CGLB
循环依赖(懒得画图解析,就多看几次源码记住。):
  • 创建一个bean的完成过程CreateBeanInstance实例化------》populateBean填充属性,上面将的autowared依赖另一个bean,将会发送getbean操作。------》InitialzeBean初始化。

  • 循环依赖主要发生在第一、二步,也就是构造器循环依赖和field循环依赖,其中构造器和prototype 原型 bean循环依赖不能被解决。 只能解决单例够朝气field循环依赖;

  • 单例模式的循环依赖:

  • (1)第一级缓存:singletonObjects。单例对象的cache。存放入完整的对象

  • (2)第二级缓存:earlySingletonObjects。提前暴光的单例对象的Cache。存放实例化但未初始化的对象,在populateBean之前。

  • (3)第三级缓存:singletonFactories。单例对象工厂缓存。存放lamda表达式,也即下面的接口,调用getObject,存放的是一个(beanNanam,创建代理对象的方法)

  • 源码分析

image.png

刚创建完成,还没初始化,放入三级缓存

image.png

image.png

从二级缓存拿出来

image.png

放入一级缓存 image.png

  • 在给B注入的时候为什么要注入一个代理对象?

  • 答:当我们对A进行了AOP代理时,说明我们希望从容器中获取到的就是A代理后的对象而不是A本身,因此把A当作依赖进行注入时也要注入它的代理对象。

  • 面试官:”为什么要使用三级缓存呢?二级缓存能解决循环依赖吗?

  • 答:如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。

Spring 事件原理

  • Refresh()>initApplicationEventMulticaster> 注册一个ApplicationEventMulticaster到容器里

  • Refresh()>registerListener>ApplicationEventMulticaster> addApplicationListener()>ListenerRetriever(回收器); addApplicationListenerBean(只是把beanName加里面)【ListenerRetriever里的getApplicationListeners触发getbean()实例化】 《〈ApplicationListenerDetector把所有的lister放入到容器里〉》

  • Refresh()--finishRefresh> publishEvent(new ContextRefreshedEvent())—》会执行这个类的SimpleApplicationEventMulticaster下面这个方法 image.png

  • InvokeListener > onApplicationEvent()>listner的方法,有自己的onApplicationEvent来进行判断当前事件是不是自己感兴趣的。也就是说发布一个事件,就会遍历所有的listner

EventListenerMethodProcessor
  • postProcessBeanFactory---》【拿到所有的EventListenerFactory】

  • afterSingletonsInstantiated-----》为打了注解的方法创建事件,并放入容器里的applicationListeners集合里。onApplicationEvent--会走到ApplicationListenerMethodAdapter。只会触发感兴趣的listner不会循环遍历所有的listner;

  • 如果要异步,要么@async 要么在实现aware接口从容器里拿到SimpleApplicationEventMulticaster.taskExecutor 进行属性复制。

Spring 中用到了什么设计模式:

  • (1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;

  • (2)Factorybean 简单工厂+装饰者

  • (3)单例模式:Bean默认为单例模式。

  • (4)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;

  • (5)观察者模式:Spring中listener的实现--ApplicationListener。

  • (6)模板方法:用来解决代码重复的问题。比如. RestTemplate。

Spring Bean的作用域之间有什么区别?

  • Spring容器中的bean可以分为5个范围。所有范围的名称都是自说明的,但是为了避免混淆,还是让我们来解释一下:

  • singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。

  • prototype:原形范围与单例范围相反,为每一个bean请求提供一个实例。

  • request:在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。

  • Session:与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。

  • request的生命周期只在数据提交,提交以后即释放,session则是浏览器关闭才释放

  • global-session:他和session的区别就是他是全局的。

  • Spring bean 的线程安全问题(spring是单例的,但并不是线程安全的)

  • 大部分的Spring bean并没有可变的状态,是线程安全的。如果bean有多个可变的状态,需要自行保证线程安全。

  • 有状态就是有数据存储功能。

  • 无状态就是不会保存数据。

  • 1、将bean的作用于“singleton”变更为“prototype”

  • 2、采用ThreadLocal进行处理,解决线程安全问题。

Factorybean 和beanFactory的区别
  • beanFactory:

  • BeanFactory是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定义了getBean()、containsBean()等管理Bean的通用方法。Spring容器在启动的时候getbean进行创建的时候需要经历完整的bean创建流程。

  • Factorybean:

  • 首先它是一个Bean,但又不仅仅是一个Bean。它是一个能生产或修饰对象生成的工厂Bean。在创建bean的时候,执行getObject方法进行创建,就这样可以绕过spring创建bean的完整流程,较为灵活。

  • 1、另外执行容器getbean方法的时候的时候getbean(“beanName”)实际是执行getobject进行创建并放入容器里返回。

  • 2、而getbean(“&beanName”)才是拿到beanName 对应的factorybean。

  • 源码分析:源码中,注意name 和beanName的区别

  • finishBeanFactoryInitialization->preInstantiateSingletons->拿到beanDefinitionNames所有的name进行实例化,在实例化之前会判断isFactoryBean(beanName)--》getBean(“&” + beanName)--》doGetBean(name)--》transformedBeanName 会吧&去掉变成beanName--->createBean会创建beanName对应的bean--> getObjectForBeanInstance--》如果name是&开头的,直接返回factorybean,如果不是-》getObjectFromFactoryBean--》doGetObjectFromFactoryBean--》object = factory.getObject()---》放入容器;

Spring 事务:
  • 1、编程式事务,在代码中硬编码。(不推荐使用)

  • 2、声明式事务,在配置文件中配置(推荐使用)

  • 这些属性都在TransactionDefinition里

image.png

  • 事务的传播行为@Transactional(propagation = Propagation.REQUIRED)

  • ① PROPAGATION_required:该设置是最常用的设置。如果当前存在事务,就直接加入该事务,如果当前没有事务,就创建一个新事务。

  • ② PROPAGATION_requires_new:创建新事务,无论当前存不存在事务,都创建新事务。

  • ③ PROPAGATION_supports:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘

  • ④PROPAGATION_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  • ⑤ PROPAGATION_mandatory(强制的):支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

  • ⑥ PROPAGATION_never:以非事务方式执行,如果当前存在事务,则抛出异常。

  • Spring中的隔离级别:

  • ① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。

  • ② ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。

  • ③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。

  • ④ ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。

  • ⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。

  • @transaction 失效场景

  • (1)、@Transactional注解作用在非public修饰的方法上,会失效。

  • 失效原因:

  • getTransactionAttribute->AbstractFallbackTransationAttributeSource的 computeTransactionAttribute

  •                                                                 if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
    
                                                                  	return null;
                                                                  }
    
  • 事务会失效但不会有任何报错。

  • (2)、多线程任务可能导致@Transaction案例失效

  • 失效原因:在被Spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。因为事务信息被绑定在多线程中,所以在父线程开启事务,子线程无法获取到父线程的事务现象,估子线程无法使用事务。

  • (3)、@Transactional注解属性propagation设置错误导致注解失效

  • 失效原因:配置错误, PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER三种事务传播方式不会发生回滚。

  • (4)、同一类中方法调用,导致@Transactional失效。

  • 失效原因:只有当事务方法被当前类以外的代码调用时,才会有Spring生成的代理对象管理。(Spring AOP代理机制造成的)。

  • (5)、@Transactional注解属性rollbackFor设置错误导致注解失效

  • rollbackFor可以指定能够触发事务回滚的异常类型。Spring默认抛出了unchecked异常(继承自RuntimeException)或者Error才会回滚事务。若事务中抛出了其他类型的异常,但却期望Spring能够回滚事务,就需要指定rollbackFor属性,否则就会失效。

  • (6)、异常被方法内catch捕获导致@Transactional失效

源码分析:底层用的切面

  • @EnableTransactionManagement-->TransactionManagementConfigurationSelector-->

  • 1、注册AutoProxyRegistrar.class代理类,注入InfrastructureAdvisorAutoProxyCreator(代理,使代理生效);

  • 2、注册ProxyTransactionManagementConfiguration,注入 TransactionAttributeSource---->point, TransactionInterceptor-->advise

    BeanFactoryTransactionAttributeSourceAdvisor{ TransactionAttributeSource, TransactionInterceptor }

    //加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立连接url(指定连接的路径 语法:“jdbc:mysql://ip地址:端口号/数据库名称”)
Connection con = DriverManager.getConnection("jdbc:mysql://10.16.158.90:3306/db1", "root", "123456");
Savepoint savepoint = null;
try {
    //创建stmt1
    Statement stmt1 = conn.createStatement();
    // 执行sql
    stmt1.executeUpdate("UPDATE accounts SET balance = balance - 100 WHERE 1=1");
    // 设置保存点
    savepoint = conn.setSavepoint("SAVEPOINT_1");
    // 创建stmt2
    Statement stmt2 = conn.createStatement();
    // 执行sql
    stmt2.executeUpdate("UPDATE accounts SET balance = balance + 100 WHERE 2=2); 
    conn.commit();
} catch (SQLException e) {
    if (savepoint != null) {
        // 回滚到保存点,保留操作1
        conn.rollback(savepoint); 
        conn.commit(); // 提交剩余操作
    } else {
        conn.rollback(); // 完全回滚
    }
} finally {
    conn.close();
}
spring 事务 主要依赖于 jdbc事务    

执行流程:

  • 先执行切面逻辑-->TransactionInterceptor->invokeWithinTransaction->

  • createTransactionIfNecessary创建事务->getTransaction里(txAttr)[事务传播机制原理]->如果该传播行为需要创建新的事物startTransactio->doBegin(开启事务)[获取jdbc connecttion]->prepareSynchronization(绑定一些重要信息到线程上下文里,如currentTransactionIsolationLevel事物隔离级别,TransactionSynchronization);--》prepareTransactionInfo 绑定TransactionInfo到线程上下文里 org.springframework.transaction.support.TransactionSynchronization TransactionSynchronization 是 Spring Framework 中一个非常重要的接口,它允许你在事务的不同阶段执行自定义的回调方法。这个接口提供了三个方法: beforeCommit(boolean readOnly):在事务提交之前被调用。 afterCommit():在事务提交之后被调用。 afterRollback():在事务回滚之后被调用。

try{

    事务执行

    }catch{

    执行异常--》completeTransactionAfterThrowing--》回滚---》或者提交事务-->会执行afterRollback():在事务回滚之后被调用。

    }finaly{

    清除事务上下文信息

   }
 commitTransactionAfterReturning-》提交事务--》会执行afterCommit():在事务提交之后被调用。
afterRollback():在事务回滚之后被调用。

@async 循环依赖问题

注意AsyncAnnotationBeanPostProcessor的父类,AbstractAdvisingBeanPostProcessor是自己实现的代理。而不是使用的AnnotationAwareAspectJAutoProxyCreator,但是用的是和他相同的方法生成代理proxyFactory.getProxy(getProxyClassLoader());

  • @EnableAsync-->AsyncConfigurationSelector-->ProxyAsyncConfiguration--->AsyncAnnotationBeanPostProcessor,注意AsyncAnnotationBeanPostProcessor虽然实现代理也是--》postProcessAfterInitialization ,但是他没实现(SmartInstantiationAwareBeanPostProcessor)的getEarlyBeanReference方法,所以不能解决循环依赖;
 public AsyncAnnotationBeanPostProcessor() {
   setBeforeExistingAdvisors(true);
 }
  • 放在所有的切面之前执行。为什么要这么设计? 比如事务,先走事务的切面,放入上下文信息,在异步开启切面,将会导致上下文信息丢失,事务不生效,所以要先走异步切面,确保事务的开启和提交在一个线程里。

  • 那就必须保证AsyncAnnotationBeanPostProcessor必须最后一个执行-> bpp.setOrder(this.enableAsync.getNumber("order")); 放入到最后一个位置。

  • Advised 是代理bean的父bean,所有的代理bean都是advised

image.png

@async 实现的也是用的切面,setBeanFactory

image.png

Springboot:
  • ApplicationListener 是spring容器启动的时间监听者

*Springboot的启动流程:SpringApplication.run>new SpringApplication()->从配置文件里加载BootstrapRegistryInitializer,ApplicationContextInitializer,ApplicationListener->

  • run>getRunListeners-->加载配置文件中SpringApplicationRunListener----》执行SpringApplicationRunListener.Starting-> prepareEnvironment-> -->listeners.environmentPrepared-----》new createApplicationContext(创建bean容器) ----》prepareContext--->listeners.contextLoaded -->刷新容器---》listeners.started—》- callRunners --》listeners.ready 容器已经刷新完成---》失败执行failed方法;
  • SpringApplicationRunListener:贯穿springboot启动的整个生命周期;Starting,environmentPrepared,contextPrepared,contextLoaded,started,ready,failed

  • Springboot 自动装配原理:

  • 源码分析

  • @SpringBootApplication->

  • 1、@ComponentScan-》(扫描主类下面所有的类)

  • 2、@SpringBootConfiguration-》@Configuration

  • 3、@EnableAutoConfiguration-》

  • @AutoConfigurationPackage 导入一个带有包路径的bean

  • @Import(AutoConfigurationImportSelector.class)

  • 源码-》process-》getAutoConfigurationEntry-》getCandidateConfigurations-》 SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration)

  • Springboot Stater:

  • blog.csdn.net/weixin_5601…

  • 启动类所在包里的bean通过ComponentScan扫描,那么其他jar包里的bean 如何扫描到呢? 1 、通过@import 导入2、 通过springboot自动配置。

BeanFactory和ApplicationContext有什么区别?
  • BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。

  • (1) BeanFactory:是Spring里面最底层的接口,包含了各种读取bean配置文档,定义bean,加载bean、创建bean,控制bean的生命周期,维护bean之间的依赖关系。

  • (2) ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

  • 支持国际化(在web开发(http协议的website/web-service)中,对于不同的语言环境给出相应的语言数据。)

  • 统一的资源文件访问方式。

  • 同时加载多个配置文件。

  • 提供在监听器中注册bean的事件。

  • (2)①BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean实例化,不能及时发现Spring的配置问题 占用内存空间小

  • (3)②ApplicationContext,它是在容器启动时,一次性实例化所有的Bean。有利于及时的发现spring的配置问题。占用内存空间大

  • (4)BeanFactory和ApplicationContext都支持BeanPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

常见注解

​注解​​触发条件​​典型应用场景​
@ConditionalOnMissingBean容器中不存在指定Bean提供默认实现
@ConditionalOnBean容器中存在指定Bean依赖其他Bean的配置
@ConditionalOnClassclasspath中存在指定类按需加载技术栈
@ConditionalOnProperty配置属性满足条件根据配置启用功能

@AutoConfigureAfter 控制bean 注册的顺序。 源码分析:OnBeanCondition

@PostConstruct 初始化资源使用。为什么要用这个注解,而不用**InitializingBean**,因为这个注解不是spring注解,减少框架依赖。单spring支持了它,源码分析:InitDestroyAnnotationBeanPostProcessor