Принцип @Transactional, который вы должны понимать и понимать

Spring Boot

1. Введение

В процессе разработки системных приложений обычно необходимо использовать транзакции для обеспечения согласованности бизнес-данных.Методы реализации: открытие транзакций, выполнение операций записи в базу данных, фиксация или откат транзакций.Этот стандартный метод реализации подходит для небольшое количество согласованных сервисов.Если существует большое количество предприятий, которым необходимо обеспечить согласованность данных, это не только заставит разработчиков повторять кодирование, но и приведет к избыточному коду в системе. На основе этих вопросов отличноSpringФреймворк предоставляет нам@TransactionalАннотации, так как же они используют аннотации для решения наших проблем? Как нам его проанализировать?

SpringBootИнтегрированные функции часто исходят изxxxAutoConfigurationначать говорить

2. Автоматическая настройка

ОткрытымTransactionAutoConfigurationКлассы автоматической настройки могут видеть более важную аннотацию@EnableTransactionManagementИспользуется для включения функции управления транзакциями,@EnableTransactionManagementАннотации снова импортируютсяAutoProxyRegistrarиProxyTransactionManagementConfiguration

2.1 Конфигурация транзакции

ProxyTransactionManagementConfigurationобъявляет аспект вBeanFactoryTransactionAttributeSourceAdvisor, убедитесь, что в касательной плоскости должны быть соответствующие точки касанияTransactionAttributeSourcePointcut(для объявления врезок) и уведомленийTransactionInterceptor(Последующие действия для достижения поставленной цели).

2.2 Заявление@TransactionalПроцессор аннотаций

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource();
}

AnnotationTransactionAttributeSourceинстанцирование указывает, что анализатор аннотацийSpringTransactionAnnotationParser

Вы можете видеть, что парсер в основном используется для обработки@Transactionalаннотация

2.3 Внедрение автоматического регистратора прокси

существует2.自动配置упомянул@EnableTransactionManagementтакже представилAutoProxyRegistrar,В направленииIOCВлить в контейнерInfrastructureAdvisorAutoProxyCreator

@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {
   return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

InfrastructureAdvisorAutoProxyCreatorДостигнутоBeanPostProcessorинтерфейс, с перехватом и дескрипторомBeanСпособность

2.3.1 BeanПостобработка

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

2.3.2 Получить все из контейнераAdvisor

/**
  * Find all candidate Advisors to use in auto-proxying.
  * @return the List of candidate Advisors
  */
protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

2.3.3 Отфильтровать подходящиеAdvisor

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    // 1.获取切点对应的MethodMatcher
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    for (Class<?> clazz : classes) {
        // 2.获取当前类中的所有方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            // 3.判断是否符合切点要求,此处的methodMatcher为TransactionAttributeSourcePointcut
            if (methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    return false;
}

Судя по тому, есть ли@TransactionalАннотация, если есть, используйтеSpringTransactionAnnotationParserразобрать и сгенерироватьTransactionAttribute

2.3.4 AdvisorСортировать

sortAdvisors(eligibleAdvisors);

2.3.4 Резюме

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 1.从容器中获取所有类型为Advisor的切面
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 2.筛选出符合条件的切面(也就是类或方法上被@Transactional注解标注)
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        // 3.对符合条件的切面进行升序排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

2.4 Выбор метода прокси

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (!IN_NATIVE_IMAGE &&
        (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
        Class<?> targetClass = config.getTargetClass();
        // 1.如果实现接口则选择jdk代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 2.选择cglib代理
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

2.4.1 Создание прокси

здесь сcglibНапример

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Class<?> proxySuperClass = rootClass;

        // Configure CGLIB Enhancer...
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
        }
        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));

        Callback[] callbacks = getCallbacks(rootClass);
    }
}
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    // Choose an "aop" interceptor (used for AOP calls).
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
}

СоздайтеEnhancerи укажите обратный вызов какDynamicAdvisedInterceptor

2.5 Вызов прокси

Выполнение целевого метода проксируемого объектаuserService.saveUser(user);будет вызван, когдаDynamicAdvisedInterceptorизintercept()метод

2.5.1 Отфильтруйте те, которые соответствуют условиямAdvice

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Advised config, Method method, @Nullable Class<?> targetClass) {
    // 1.遍历所有满足条件的Advisor,也就是2.3.3章节返回的Advisor
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // Add it conditionally.
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                // 2. 判断是否满足切点要求
                boolean match = mm.matches(method, actualClass);
                // 3.满足切点要求
                if (match) {
                    // 3. 获取切面对应的通知,也就是TransactionInterceptor
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
        }
    }
	// 4.返回满足条件的通知
    return interceptorList;
}

2.5.2 Выполнение условногоAdvice

@Override
@Nullable
public Object proceed() throws Throwable {
	// 1.如果没有advice可以执行,则执行目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    // 2.从advice列表中取出一个advice
    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    // 3.执行advice的invoke方法,也就是TransactionInterceptor的invoke
	return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

3. Вызов транзакции

3.1 Получить свойства конфигурации транзакции

TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

это@TransactionalСвойства, объявленные в аннотациях

3.2 Получить диспетчер транзакций

final TransactionManager tm = determineTransactionManager(txAttr);

получить из контейнераDataSourceTransactionManagerAutoConfigurationМенеджер транзакций, объявленный в классе автоконфигурацииJdbcTransactionManager

public class DataSourceTransactionManagerAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(TransactionManager.class)
    JdbcTransactionManager transactionManager(DataSource dataSource,
                                              ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
        JdbcTransactionManager transactionManager = new JdbcTransactionManager(dataSource);
        transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
        return transactionManager;
    }
}

3.3 Выполнение транзакций

4. Резюме

@TransactionalТри элемента принципа реализации切面,切点,通知

  • InfrastructureAdvisorAutoProxyCreatorПостпроцессор перехватывает всеBean
  • Итерация по всем типамAdvisorиз切面
  • вернуться довольным切点условный切面список
  • Выберите метод прокси
  • Создать прокси
  • перечислить通知изinvoke()метод
    • открытая транзакция
    • позвонить другим通知изinvoke()метод, если целевой метод не выполняется
    • Выполнить исключение, откатить транзакцию
    • Выполнить успешно, зафиксировать транзакцию
  • Выполнить целевой метод

учиться@TransactionalПринцип реализации аннотаций позволяет не только切面,切点,通知Четкое понимание также позволяет нам выполнять аналогичные функции с помощью его идей, таких как@CacheАннотации реализуют кэширование приложений,@AsyncАннотация реализует асинхронное выполнение бизнеса