在Java中,如果在同一个类中直接调用另一个带有注解的方法,比如@Async或@Transactional,注解通常不会生效。这是因为这些注解通常是通过Spring的AOP(面向方面编程)来实现的,而AOP代理对象只能拦截外部对目标对象的方法调用,而不能拦截内部方法调用。
原因
Spring在处理这些注解时,会生成一个代理对象来管理事务、异步操作等。如果你在同一个类中直接调用带有这些注解的方法,本质上是在调用同一个对象的方法,而不是通过代理对象调用的,因此这些注解不会生效。
解决方案
1. 使用AOP注解的方法放到另一个Bean中
一种方法是将带有这些注解的方法移到另一个Spring管理的Bean中,然后通过依赖注入调用该Bean的方法。
例如:
@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应用上下文来获取自身的代理对象并调用方法。
例如:
@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代理。
@Configurable public class MyService { public void myMethod() { asyncMethod(); } @Async public void asyncMethod() { // 你的异步代码 } }
在Spring配置中启用AspectJ代理:
xml复制代码 <bean id="configurableAnnotationProcessor" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/> <context:load-time-weaver aspectj-weaving="on"/>
总结
在同一个类中直接调用带有AOP注解的方法时,这些注解通常不会生效。可以通过将方法移到另一个Bean、通过Spring上下文获取自身代理对象或使用@Configurable
注解等方式解决这个问题。
完整的测试代码:
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()); } }