起因:有时候我们有这样的需求,在一个事务方法中调用了其他类的某个方法,但希望这个方法再事务提交后执行。
思考:被调用的方法,肯定要做到延迟执行,可以把执行的方法放入ThreadLocal里,等事务提交后拿出来执行,但怎么判断事务已经提交了呢,这个就要用到spring 事务处理的AbstractPlatformTransactionManager类里面的回调功能
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
boolean globalRollbackOnly = false;
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
globalRollbackOnly = status.isGlobalRollbackOnly();
}
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
doCommit(status);
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (globalRollbackOnly) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
// can only be caused by doCommit
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
catch (Error err) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, err);
throw err;
}
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
cleanupAfterCompletion(status);
}
}
上面的trtriggerAfterCommit(status);就是处理事务提交后的动作处理,继续跟踪发现是调用
TransactionSynchronizationUtils 的下面方法
public static void invokeAfterCommit(List<TransactionSynchronization> synchronizations) {
if (synchronizations != null) {
for (TransactionSynchronization synchronization : synchronizations) {
synchronization.afterCommit();
}
}
}
synchronizations参数是通过 TransactionSynchronizationManager.getSynchronizations()获得的真是从ThreadLoca获取的对象是TransactionSynchronization。
解决方法:自定义注解,在切面拦截有注解 的方法,并把待调用的方法封装到下面的这个类里并且执行execute方法,把当前方法设置到TransactionSynchronizationManager。最后再回调方法执行。
public class AfterCommitExecutorImpl extends TransactionSynchronizationAdapter implements AfterCommitExecutor {
private static final Logger LOGGER = Logger.getLogger(AfterCommitExecutorImpl.class);
private static final ThreadLocal<List<Runnable>> RUNNABLES = new ThreadLocal<List<Runnable>>();
@Override
public void execute(Runnable runnable) {
LOGGER.info("Submitting new runnable {"+runnable+"} to run after commit");
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
LOGGER.info("Transaction synchronization is NOT ACTIVE. Executing right now runnable {"+runnable+"}");
runnable.run();
return;
}
List<Runnable> threadRunnables = RUNNABLES.get();
if (threadRunnables == null) {
threadRunnables = new ArrayList<Runnable>();
RUNNABLES.set(threadRunnables);
TransactionSynchronizationManager.registerSynchronization(this);
}
threadRunnables.add(runnable);
}
@Override
public void afterCommit() {
List<Runnable> threadRunnables = RUNNABLES.get();
LOGGER.info("Transaction successfully committed, executing {"+threadRunnables.size()+"} runnables" );
for (int i = 0; i < threadRunnables.size(); i++) {
Runnable runnable = threadRunnables.get(i);
LOGGER.info("Executing runnable {"+runnable+"}");
try {
runnable.run();
} catch (RuntimeException e) {
LOGGER.error("Failed to execute runnable " + runnable, e);
}
}
}
@Override
public void afterCompletion(int status) {
LOGGER.info("Transaction completed with status {"+(status == STATUS_COMMITTED ? "COMMITTED" : "ROLLED_BACK")+"}");
RUNNABLES.remove();
}
相关推荐
System.out.println("在执行方法后,处理自定义注解:" + customAnnotation.value()); return result; } } ``` 在这个例子中,`@Around("@annotation(customAnnotation)")`表示我们的通知将在标记了`Custom...
// 方法执行后记录日志 long elapsedTime = System.currentTimeMillis() - start; System.out.println("方法结束,执行时间:" + elapsedTime + "ms"); return result; } catch (Exception e) { // 记录异常...
`@Before`、`@After`、`@AfterReturning`、`@AfterThrowing`和`@Around`分别代表在方法执行前、执行后(无论是否成功)、正常返回后、抛出异常后和环绕方法执行时运行的代码。 例如,我们可以使用`@Before`注解实现...
首先,让我们关注"注解事务"。在Spring框架中,我们主要依赖`@Transactional`注解来声明事务边界。当一个方法被这个注解标记时,Spring会自动管理事务的开始、提交或回滚。如果方法中发生任何未捕获的异常,事务将被...
在Spring Boot应用中,我们可以通过自定义注解和Spring AOP(面向切面编程)来实现这一功能。下面将详细解释这个主题。 首先,了解Spring AOP的概念。AOP是面向切面编程,它允许我们在不修改源代码的情况下,通过预...
- **通过`order`属性调整切面的优先级**:为了确保事务能够正常工作,我们需要保证事务管理器切面的执行优先级高于其他自定义切面。这可以通过设置`order`属性来实现。`order`值越小,表示优先级越高。 4. **示例...
在文章中,使用 AspectJ 来织入自定义注解 SecureValid,以便在方法执行前后执行相应的处理逻辑。 Spring AOP 自定义注解的实现代码中还涉及到 Maven 依赖管理、spring-aop 和 aspectjrt 等库的使用。这些库提供了...
- AOP切面:`@Transactional`指定方法应在事务中执行。 在TestAnnotation项目中,你可以找到一个具体的自定义注解案例,包括注解的定义、使用和通过反射进行解析的示例代码。通过研究这个案例,你将更深入地理解...
Java自定义注解是Java平台提供的一种元数据机制,它允许程序员在代码中添加额外的信息,这些信息可以被编译器、JVM或其他工具在编译时或运行时读取,用于实现各种功能,如代码生成、代码分析、依赖注入等。自定义...
- 自定义注解可以结合AOP实现切面,如`@Before`、`@After`、`@Around`等,定义在哪些方法之前、之后或环绕执行特定操作。 6. **实例应用** - 创建一个自定义的`@MyController`注解,用于标记控制器类,然后编写...
自定义事务管理器需要实现`PlatformTransactionManager`接口,并提供开始、提交、回滚事务的方法。同时,你可以定义自定义的事务注解,以实现更灵活的事务控制。 例如,假设你创建了一个名为`...
为了实现数据库切库,我们需要创建一个自定义注解,用于标记需要切换数据库的方法,并编写相应的拦截器来处理这些注解。 1. **创建自定义注解**: 创建一个新的Java注解,例如`@DatabaseSwitch`,它包含一个属性,...
自定义注解可以附加在方法上,当该方法被调用时,AOP会捕获这个调用并执行相应的逻辑,即切换到指定的数据源。 具体实现步骤如下: 1. 定义数据源配置:创建多个DataSource配置,每个数据源对应不同的数据库连接...
例如,通过Shiro的自定义注解,可以在方法级别进行权限判断,确保只有具有特定权限的用户才能执行特定的操作。这在描述中提到的"自定义注解权限控制"就是指这一功能。 MyBatis Plus则是在MyBatis的基础上扩展的一套...
1. **注解方式声明事务**:Spring提供了`@Transactional`注解,可以将其添加到方法级别或类级别,以声明该方法或类需要在事务上下文中执行。例如: ```java @Service public class UserService { @Transactional ...
总结起来,通过定义一个自定义注解来标记需要拦截的方法,并通过AOP配置来指定拦截器的执行时机和方法,可以灵活地在Spring MVC应用中添加各种前置处理逻辑,而不影响核心业务代码的清晰和专注。这种方式不仅可以...
自定义命令执行器就是一种实现业务解耦的方式,它提供了一个通用的接口,用于执行各种特定任务,而不是直接引用具体的业务类或方法。 2. **命令执行器**:命令执行器是一个设计模式,它的核心思想是将命令(即方法...
通过在控制器方法上使用自定义注解,拦截器可以检测并执行相应的逻辑,例如检查用户是否已登录。 2. **注解+AOP(面向切面编程)** 自定义注解可以与Spring AOP结合,用于实现特定的切面逻辑。例如,可以创建一个`...
在Spring框架中,事务管理是实现业务逻辑时不可或缺的一部分,它确保了数据的一致性和完整性。Spring提供了多种事务管理方式,其中基于注解的事务管理是近年来常用的模式,因为它简化了代码并提高了可读性。本文将...
2. 后置通知(@After):在目标方法执行后,无论其是否抛出异常都会执行。常用于清理工作,如关闭资源。`@After`注解的方法会在目标方法执行完毕后运行。 3. 返回后通知(@AfterReturning):在目标方法正常返回后执行...