Ходила сегодня к стоматологу, и он спросил меня, почему мои светлые зубы так сильно изношены? Я сказал, что приходил сюда со стиснутыми зубами в те годы, когда не поднимал большого пальца вверх.
Введение в аннотацию @Transactional
@Transactional
Это метод настройки аннотаций для декларативного управления транзакциями в spring Я думаю, что все знают роль этой аннотации.@Transactional
Аннотации могут помочь нам управлять операциями открытия, фиксации или отката транзакций через aop.
пройти через@Transactional
Аннотации позволяют Spring управлять транзакциями за нас, устраняя повторяющуюся логику управления транзакциями, уменьшая вмешательство в бизнес-код и позволяя нашим разработчикам сосредоточиться на разработке на уровне бизнеса.
Мы знаем, что для достижения принципа @transactional основана на Spring AOP, AOP - это модель динамического агентства, посредством чтения исходного кода, суммировавшими следующие шаги, чтобы понять реальность, как использование весной AOP для достижения @transactional функций Отказ
Гипотеза о принципе реализации декларативной транзакции в spring
Прежде всего, если у вас есть понимание принципа реализации aop в spring, вы должны знать, что если вы хотите проксировать метод, вы должны определить pointcut. В реализации @Transactional то же самое, Spring определяет для нас pointcut с аннотацией @Transactional в качестве точки имплантации, чтобы мы могли знать, что метод, аннотированный аннотацией @Transactional, должен быть проксирован.
С определением аспекта в процессе инициализации bean-компонента Spring необходимо проксировать созданный bean-компонент и создать прокси-объект.
В прокси-логике для генерации прокси-объектов при вызове метода необходимо сначала получить логику аспекта.Аспектная логика аннотации @Transactional аналогична @Around, которая реализует аналогичную логику прокси в spring.
@Транзакционная роль
Согласно вышеуказанному принципу гипотезе, следующее представляет собой краткое введение в исходный код каждого шага для проверки.
Первый — это @Transactional, определяющий точку имплантации прокси. Мы знаем, что прокси-объект создаетсяBeanPostProcessor
класс реализацииAnnotationAwareAspectJAutoProxyCreator
изpostProcessAfterInstantiation
метод для достижения этого, если требуется проксирование, то этот метод вернет прокси-объект в контейнер, и точка имплантации суждения также находится в этом методе.
Затем начните анализ ниже.После настройки управления транзакциями на основе аннотаций Spring создастBeanFactoryTransactionAttributeSourceAdvisor
Например, этот экземпляр можно рассматривать как pointcut.При оценке необходимости создания bean-компонентом прокси-объекта в процессе инициализации его необходимо проверить один раз.BeanFactoryTransactionAttributeSourceAdvisor
Это PointCut для этого боба. Если это так, вам нужно создать прокси-объект и поставитьBeanFactoryTransactionAttributeSourceAdvisor
Экземпляр внедряется в прокси-объект.
Мы знаем до этогоAopUtils#findAdvisorsThatCanApply
Чтобы определить, применим ли аспект к текущему компоненту, вы можете поставить точку останова и проанализировать стек вызовов в этом месте.AopUtils#findAdvisorsThatCanApply
Последовательно вызовите и, наконец, оцените, применим ли pointcut, с помощью следующего кода.
-
AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class<?> targetClass)
Здесь можно ставить условные точки останова на параметры для отладки и анализа стека вызовов, targetClass — целевой класс… серия вызовов - наконец-то
SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
//这里就是分析Method是否被@Transactional注解标注,有的话,不用说BeanFactoryTransactionAttributeSourceAdvisor适配当前bean,进行代理,并且注入切点
//BeanFactoryTransactionAttributeSourceAdvisor
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
Выше приведен процесс оценки необходимости создания прокси-объекта в соответствии с @Transactional. Одна из функций @Transactional состоит в том, чтобы определить, что метод должен быть проксирован, а другая — в том, чтобы нести некоторую атрибутивную информацию, необходимую для управления транзакциями.
Реализация логики динамического прокси
[Анализ принципа реализации аоп], мы знаем, что прокси-метод конечного прокси-объекта аоп
DynamicAdvisedInterceptor#intercept
Таким образом, мы можем проанализировать логику прокси в этой точке останова метода.
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
//follow
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
после анализаList<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
Возвращает TransactionInterceptor, как добиться логических вызовов прокси-сервера TransactionInterceptor?
отслеживатьnew CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
найти, что последний вызовTransactionInterceptor#invoke
метод и внедрить CglibMethodInvocation в метод вызова, как вы можете видеть из приведенного вышеCglibMethodInvocation
Упаковка всей необходимой информации Объект 'вызывает, следовательно,TransactionInterceptor#invoke
Целевой метод также может вызываться внутри, также может быть реализована логика, аналогичная @Around, и может продолжаться внедрение некоторой другой логики, например логики управления транзакциями, до и после вызова целевого метода.
Обратите внимание на общедоступный номер [Скучно изучать Java], чтобы получать последние видео о галантерейных товарах.
TransactionInterceptor — лучший менеджер транзакций
См. код ниже.
TransactionInterceptor#invoke
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
Продолжайте отслеживать invokeWithinTransaction.На самом деле, некоторые логические подсказки можно увидеть в следующем коде, который является методом реализации нашего предположения, управления транзакциями.
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
//开启事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//方法调用
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//回滚事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
//提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
return new ThrowableHolder(ex);
}
}
finally {
cleanupTransactionInfo(txInfo);
}
}
});
// Check result: It might indicate a Throwable to rethrow.
if (result instanceof ThrowableHolder) {
throw ((ThrowableHolder) result).getThrowable();
}
else {
return result;
}
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
}
}
Суммировать
Наконец, вы можете обобщить весь процесс и сравнить его с первоначальным предположением.
После анализа исходного кода