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 的启动流程:
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) 框架,其核心原理是通过 字节码增强 在编译期、类加载期或运行时动态植入切面逻辑。
-
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
-
静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
-
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
JDK代理
- 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.父类方法。
生成的子类大概如下
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,创建代理对象的方法)
-
源码分析
刚创建完成,还没初始化,放入三级缓存
从二级缓存拿出来
放入一级缓存
-
在给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下面这个方法
-
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里
-
事务的传播行为@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
@async 实现的也是用的切面,setBeanFactory
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:
-
启动类所在包里的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的配置 |
@ConditionalOnClass | classpath中存在指定类 | 按需加载技术栈 |
@ConditionalOnProperty | 配置属性满足条件 | 根据配置启用功能 |
@AutoConfigureAfter 控制bean 注册的顺序。 源码分析:OnBeanCondition
@PostConstruct 初始化资源使用。为什么要用这个注解,而不用**InitializingBean**,因为这个注解不是spring注解,减少框架依赖。单spring支持了它,源码分析:InitDestroyAnnotationBeanPostProcessor