2012-07-20 132 views
2

我需要一個服務(單身符合)與一些內部字段,如待處理線程列表(是的一切都寫成線程安全)問題是,如果我@autowire這個bean,字段似乎是空的。調試我發現代理正確地綁定到實例(字段CGLIB$CALLBACK_X正確鏈接到填充的bean)並填充字段,但它提供的字段爲空。春天單身豆字段不填充

以下幾行代碼給出了我正在談論的一般概念。

@Service 
public class myService{ 

    @Autowired 
    private Monitor monitor; 

    public List getSomething(){ 
     return monitor.getList(); 
    } 
} 


@Service 
public class myStatefulService{ 

    //This field will be populated for sure by someone before getSomething() is called 
    private List list; 

    public synchronized List getSomething(){ 
     return this.list; 
    } 

    //Called by other services that self inject this bean 
    public synchronized void addToList(Object o){ 
     this.list.add(o); 
    } 
} 

中的GetList通話過程中調試變量monitor我得到

monitor => instance of correct class 
fields: 
    CGLIB$BOUND => true 
    CGLIB$CALLBACK_0.advised => proxyFactory (correct) 
    CGLIB$CALLBACK_1.target (reference to the correct instance of myStatefulService class) 
     fields: 
      list => [.........] (correctly populated) 
    CGLIB$CALLBACK_2 ..... 
    ...... 
    ...... 
    ...... 
    list => [] (the list that would be populated is empty instead) 

回答

8

你好奇還是有一些真正的問題?儘管如此,這是一個解釋。

當使用CGLIB代理類時,Spring將創建一個名爲myService$EnhancerByCGLIB的子類。這個增強的類將覆蓋一些(如果不是全部)商業方法,以便在您的實際代碼中應用橫切關注點。

這裏是真正的驚喜。這個額外的子類不會調用基類的super方法。相反,它創建myService的第二個實例並委託給它。這意味着你現在有兩個對象:你的真實對象和CGLIB增強對象指向(包裝)它。

增強型類僅僅是一個虛擬代理。它仍然有和你的基類相同的字段(從它繼承),但它們不被使用。當您在myService$EnhancerByCGLIB對象上調用addToList()對象時,它將首先應用一些AOP邏輯,調用addToList()myService(將其封裝),並在返回時應用剩餘的AOP邏輯。 myService$EnhancerByCGLIB.list字段永遠不會被觸及。

爲什麼春不能使用相同的班級並通過super委託?我想爲了簡單起見:首先創建「raw」bean,然後在後處理期間應用AOP代理。

4

「該字段會被別人getSomething填充之前肯定()被稱爲」

通過別人?不,春豆廠。如果您不配置它,則不會填充任何內容。

不是每個bean都需要受Spring的控制。這聽起來像你想有一個List客戶端可以添加和刪除項目以線程安全的方式。如果是這樣,請刪除@Autowired註釋,創建新的List,並公開要添加和刪除的方法。

我建議從新的併發集合列表。

+0

對不起,列表中的@autowired是一個打字錯誤....一切都在Spring的控制之下,「某人」是一種響應客戶端動作的其他服務......所以客戶端使用其他服務向列表添加元素。帶有列表的服務包含邏輯並定期在列表上工作,所以我需要成爲一個singleton可注入有狀態bean =) – Gnappuraz 2012-07-20 14:22:18

+0

是的,我提供了添加元素到列表的方法,但是當列表被讀取時它也是空的,如果代理指向的實例已正確填充它。 – Gnappuraz 2012-07-20 14:29:01

+0

爲什麼你需要一個代理?我會說這是一個不需要由Spring控制的對象的例子。只是實例化一個新的並繼續下去。 – duffymo 2012-07-20 16:50:26

0

CGLIB將代理受保護的獲得者。

所以,你可以有:

@Autowired 
private Monitor monitor; 

protected Monitor getMonitor() { return monitor; } 

public List getSomething(){ 
    return getMonitor().getList(); 
} 

getMonitor()將被代理到在具有顯示器注入另一實例調用getMonitor()。