切換語言為:簡體

在Java同一個類中,一個方法呼叫另外一個有註解的方法,註解不生效原因分析

  • 爱糖宝
  • 2024-06-04
  • 2083
  • 0
  • 0

在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. 使用@ConfigurableSpring 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());
    }

}

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.