Spring同一個類中注解方法互相調用的問題


 

 

    在使用Spring時,很多初學者不了解Spring對象注入的機制和面向切面編程的原理,很容易犯一些錯誤。下面就是初學者最容易犯的錯誤。舉例如下:

@Component

public class TestClass {
    private Random random = new Random();
    @Cacheable("cache1")
    public String getData(String key){
        System.out.println("load data from file, key = " + key);
        return  key + key;
    }
    @Scheduled(fixedDelay = 100)
    public void task(){
        int rand = random.nextInt(100);
        String strParam = String.format("%d", rand);
        String str = getData(strParam);
        System.out.println("result is " + str);
    }
}

 

 

    這里TestClass類里同時啟用了Scheduled注解和@Cacheable注解。如果在外面其他類中調用getData(...)時,緩存機制會生效,但是在task函數內部調用getData(...)時,緩存機制不會生效。網上有人把這歸納為:不能在同一個類中互相調用注解過的方法,否則注解失效。

 

    為什么會有這樣的差別呢?背后的原因就是Spring的對象注入機制。

    當外部通過@Autowired注解得到一個TestClass對象時,其實得到的是一個Spring包裝過的代理對象。如下圖所示。 

    當調用Obj.getData時,實際調用的是Spring的Proxy對象中的getData方法,該方法內置了Cache機制,在Cache檢查后就會調用實際的TestClass對象中的getData方法。

    同理通過@Scheduled注解表示這是一個任務調度時,Spring Proxy對象中會初始化對應的調度線程池等工作,當觸發調度條件時,再調用實際的TestClass對象。

    但是當在實際的TestClass對象中再調用getData時,不會觸發Cache機制,因為此時不是調用的SpringCacheProxy對象,而是一個實際的TestClass對象,所以不會觸發Cache機制。

    如果大家深入去讀Spring完成注入和AOP編程實現的原理,可以發現動態代理是很重要的一個技術。目前Spring的動態代理主要是通過CGLib來實現的。后面我會再寫CGLib的實現思路。

    那么我們該如何避免出現上述問題呢?

    首先我們應該牢記一個原則:同一個類中的注解方法互相調用時,注解機制可能是無效的。

    對於上述示例,我們可以把其拆分為兩個類來實現,一個類完成任務調度、一個類完成Cache機制。這樣在任務調度中調用的是Spring實現了Cache機制的代理類,可以確保其Cache機制生效。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM