持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
直入主题
我们想要了解spring的事务原理,首先从注解EnableTransactionManagement入手:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// ********这是重点********这是重点********这是重点********这是重点********
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// 这个就决定了是用JDK代理还是CGLIB代理
// false就是使用JDK代理,针对接口代理
// true就是直接针对实现类代理
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
// 默认是PROXY,所以直接看ProxyTransactionManagementConfiguration这个类
@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;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
// 主要关注如何创建BeanFactoryTransactionAttributeSourceAdvisor
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
// 创建一个BeanFactoryTransactionAttributeSourceAdvisor对象,这样的话,在BeanPostProcessor中就可以被获取到,并且针对匹配到的class和method进行增强
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;
}
// TransactionAttributeSource创建出来后,是要设置进BeanFactoryTransactionAttributeSourceAdvisor的
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
//TransactionInterceptor创建出来,也是要设置进BeanFactoryTransactionAttributeSourceAdvisor,所以中点还是在上面
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
在创建出来的BeanFactoryTransactionAttributeSourceAdvisor中,最主要的就是pointcut和advice,这两个正好组合成一个Advisor。pointcut表示逻辑切入点,advice表示真正的拦截逻辑。
当前我们所了解的代码中,TransactionInterceptor正好作为一个advice被设置进BeanFactoryTransactionAttributeSourceAdvisor中,那么pointcut是如何被设置进去的呢?
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
// pointcut是BeanFactoryTransactionAttributeSourceAdvisor对象被创建的时候就直接默认TransactionAttributeSourcePointcut
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
// 创建出来的pointcut依赖于设置进来的transactionAttributeSource
return transactionAttributeSource;
}
};
在spring AOP的实现当中,有一个findAdvisorsThatCanApply()方法,作用是从一系列Advisor中筛选出合适的Advisor实例
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 主要是这个方法
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
AopUtils
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 看这里,主要是通过这里来判断。只要目标class或者任何的method被Transactional注解,就返回true
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
// ******这是重点***********这是重点***********这是重点***********这是重点*****
// BeanFactoryTransactionAttributeSourceAdvisor通过getPointcut()方法获取TransactionAttributeSourcePointcut实例
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 在TransactionAttributeSourcePointcut中,getMethodMatcher()方法就是返回this,也就是TransactionAttributeSourcePointcut本身
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
// TransactionAttributeSourcePointcut不是IntroductionAwareMethodMatcher类型
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 通过matches()方法判断目标类中的每一个方法,TransactionAttributeSourcePointcut调用matches()方法,其实就是判断当前方法有没有被Transactional注解。只要有一个方法被Transactional注解,就直接返回true
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
在上述代码中,主要的目标就是找到pointcut,只要被@Transactional注解的class或method都会被作为pointcut。
到这里的话,spring事务是如何织入的基本就讲述完毕了。