spring源码解读系列
Spring源码解读:@Transactional原理(1)
Spring源码解读:@Transactional原理(2)
前言
大家都知道Spring的两大法器:Context + Proxy;下面简单介绍下Spring是如何做到的
一、proxy是什么
proxy对raw bean进行代理,对被代理的方法进行增强,实现一些额外的逻辑。
譬如常用@Transactional注解,就是通过proxy实现进行简单的dao层代码调用就实现了数据库事务的提交。
二、spring实现proxy的过程
如spring循环依赖原理图解+bean的生命周期图解图里所示,一个普通的bean,是在bean生命周期最后一步才进行proxy;如果发生了循环依赖,就会在被注入到其他bean之前提前进行proxy。 那为什么又会出现添加@Async注解,导致spring启动失败问题呢?
2.1.最后一步的proxy
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
java
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;
}
java
public interface BeanPostProcessor {
//------------ignore something---------------
/**
* bean的生命周期最后一步,目前主要用来执行proxy
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
在bean的生命周期,最后一步的proxy就是通过调用BeanPostProcessor#postProcessAfterInitialization来实现的
2.2.提前注入proxy
其实是在bean的生命周期,提前放入到一级缓存里的supplier,当supplier.get()时返回提前代理对象,所以我们看看放入到一级缓存里的supplier是什么
java
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 返回一个进行了aop处理的ObjectFactory,提前暴露
// 但是只有当该实例在创建过程中还被其他实例引用(循环依赖),才会被调用getEarlyBeanReference
// 此处是第四次调用beanPostProcessor,不一定会调用,只有当该类真的在创建过程中被其他类当做属性所依赖
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
当允许循环依赖的时候,往一级缓存里放置一个getEarlyBeanReference
java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
真到注入的时候,执行SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference返回proxy bean,大家可能会问了,这也不是通过BeanPostProcessor#postProcessAfterInitialization来返回的proxy bean啊,怎么保证proxy的逻辑一致。 别着急,我们来看看SmartInstantiationAwareBeanPostProcessor的子类AbstractAutoProxyCreator
java
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 对bean进行proxy操作
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
可以看到不管是放到一级缓存里的还是生命周期的proxy逻辑,都是执行wrapIfNecessary,所以逻辑是一致的,同时为了防止多次proxy,还用earlyProxyReferences记录了已经proxy的bean。
2.3. 为什么@Async注解不行?
再观察下上面的代码,可以发现,
- 提前放入一级缓存的是通过执行SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference进行proxy,
- 最后一步的代理是通过执行BeanPostProcessor#postProcessAfterInitialization进行proxy。
- 如果某个xxxbeanPostProcessor是BeanPostProcessor的实现类,却不是SmartInstantiationAwareBeanPostProcessor的实现类,会发生什么?
问题发生了 :注入到其他bean里的是raw bean,或者是half proxy bean;而等当前bean执行到最后一步proxy的时候,获取到的是一个完整proxy bean。然后spring容器中就同一个beanName得到了两个不同的对象,那怎么可以,毕竟spring容器默认是单例的!!!
而我们针对bean进行@Async功能增加的AsyncAnnotationBeanPostProcessor就是这样一个类
2.4. proxy工具类关系图

三、为什么@Transactional可以
可能大家也看出差别了,如果是通过往spring容器里注入的是一个Advisor,或者@Aspect,这种都是SmartInstantiationAwareBeanPostProcessor来帮忙处理,也会在getEarlyBeanReference暴露。
3.1 @EnableTransactionManagement
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
//------ignore something
}
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
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;
}
}
//------ignore something
}
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
//-----------ignore something
return advisor;
}
}
可以看到@EnableTransactionManagement是通过ProxyTransactionManagementConfiguration往spring容器中放了一个Advisor:BeanFactoryTransactionAttributeSourceAdvisor
3.2 @EnableAsync
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
//------ignore something
}
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
// 默认看此处逻辑
return new String[] {ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
//--------ignore something
return bpp;
}
}
可以看到@EnableAsync是通过ProxyAsyncConfiguration往spring容器中放了一个AsyncAnnotationBeanPostProcessor
总结
更深度的分析了下@Async注解在循环依赖场景为什么会可能导致spring容器启动失败,欢迎探讨~