在Java中,如果在同一个类中直接调用另一个带有注解的方法,比如@Async或@Transactional,注解通常不会生效。这是因为这些注解通常是通过Spring的AOP(面向方面编程)来实现的,而AOP代理对象只能拦截外部对目标对象的方法调用,而不能拦截内部方法调用。
原因
Spring在处理这些注解时,会生成一个代理对象来管理事务、异步操作等。如果你在同一个类中直接调用带有这些注解的方法,本质上是在调用同一个对象的方法,而不是通过代理对象调用的,因此这些注解不会生效。
解决方案
1. 使用AOP注解的方法放到另一个Bean中
一种方法是将带有这些注解的方法移到另一个Spring管理的Bean中,然后通过依赖注入调用该Bean的方法。
例如:
java
@Service
public class MyService {
@Autowired
private AnotherService anotherService;
public void myMethod() {
anotherService.asyncMethod();
}
}
@Service
public class AnotherService {
@Async
public void asyncMethod() {
// 你的异步代码
}
}
2. 使用AOP自调用
如果不想将方法移到另一个Bean中,可以通过Spring应用上下文来获取自身的代理对象并调用方法。
例如:
java
@Service
public class MyService {
@Autowired
private ApplicationContext applicationContext;
public void myMethod() {
MyService self = applicationContext.getBean(MyService.class);
self.asyncMethod();
}
@Async
public void asyncMethod() {
// 你的异步代码
}
}
3. 使用@Configurable
和Spring AOP
这种方法相对复杂一些,可以在类上使用@Configurable
注解,然后在Spring配置中启用AspectJ代理。
java
@Configurable
public class MyService {
public void myMethod() {
asyncMethod();
}
@Async
public void asyncMethod() {
// 你的异步代码
}
}
在Spring配置中启用AspectJ代理:
xml
xml复制代码
<bean id="configurableAnnotationProcessor"
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<context:load-time-weaver aspectj-weaving="on"/>
总结
在同一个类中直接调用带有AOP注解的方法时,这些注解通常不会生效。可以通过将方法移到另一个Bean、通过Spring上下文获取自身代理对象或使用@Configurable
注解等方式解决这个问题。
完整的测试代码:
java
package com.minp.admin.task.standingbook;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* @功能描写: 测试异步注解任务
* @Author ****
* @Versions 1.0
* @Data: 2024/6/4 10:32
* @项目名称: ****
*/
@Component
@Log4j2
public class TestAsyncAnnotationTask {
private final ApplicationContext applicationContext;
public TestAsyncAnnotationTask(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void testAsyncAnnotationTask() {
log.info("测试异步注解任务--开始");
log.info("当前线程名称-{}", Thread.currentThread().getName());
test1();
applicationContext.getBean(TestAsyncAnnotationTask.class).test2();
}
@Async
public void test1() {
log.info("调用了test1");
log.info("当前线程名称-{}", Thread.currentThread().getName());
}
@Async
public void test2() {
log.info("调用了test2");
log.info("当前线程名称-{}", Thread.currentThread().getName());
}
}