2012-07-16 222 views
6

我們使用Spring的TransactionInterceptor設置每當執行標有@Transactional標註一個DAO方法使用ThreadLocal一些數據庫分區信息。我們需要這樣才能將查詢路由到不同的數據庫分區。Spring bean如何檢測它本身是否被包裝在AOP代理中?

這工作對大多數DAO方法:

// this causes the invoke method to set a thread-local with the host name of 
// the database server the partition is on 
@Transactional 
public int deleteAll() throws LocalDataException { 

的問題是,當我們需要引用DAO內的DAO 代理對象本身。通常情況下,我們必須讓代理通過代理服務:

public Pager<Foo, Long> getPager(FooDao proxyDao) { 

這看起來像下面的代碼顯然很粗糙。

fooDao.getPager(fooDao); 

的問題是,當我們FooDao的內部,this代理DAO,我們所需要的。

有沒有更好的機制,一個bean來發現它周圍有一個代理包裝?我已經看過Spring AOPUtils,但我看不到一個對象的代理。例如,我不想要isAopProxy(...)。我也讀過Spring AOP docs,但是除非我實現我自己希望避免的AOP本地代碼,否則我不能在那裏看到解決方案。

我懷疑我可能可以通過ApplicationContextAware實用程序bean和setProxyDao(...)方法將DAO注入自身,但這看起來也像是黑客攻擊。任何其他的想法如何我可以檢測代理,所以我可以利用它從bean本身?謝謝你的幫助。

+0

正在使用本地Aspectj加載/編譯時編織不是一個選項 - 然後建議將編織到代理,你不應該有一個代理和代理內的此引用的問題? – 2012-07-16 18:19:51

+0

'this'不會做@Thorbjørn,因爲正如帖子所述,我需要代理_not_ bean本身。 – Gray 2012-07-16 18:23:02

+0

寫我自己的本地AOP可能是我唯一的解決方案@Biju。如果可以的話,我希望避免它。感謝壽。 – Gray 2012-07-16 18:24:38

回答

4

沿着你所建議的是什麼線哈克解決方案,考慮到AspectJ的編譯時間或加載時間編織不會爲你工作:

創建沿着這些線路的接口:

public interface ProxyAware<T> { 
    void setProxy(T proxy); 
} 

設你道的貫徹落實ProxyAware,現在創建了BeanPostProcessor與有序接口,最後跑,沿着這些線路:

public class ProxyInjectingBeanPostProcessor implements BeanPostProcessor, Ordered { 
    @Override 
    public Object postProcessBeforeInitialization(Object bean, String beanName) { 
     return bean; 
    } 

    @Override 
    public Object postProcessAfterInitialization(Object bean, String beanName) { 
     if (AopUtils.isAopProxy((bean))){ 
      try { 
       Object target = ((Advised)bean).getTargetSource().getTarget(); 
       if (target instanceof ProxyAware){ 
        ((ProxyAware) target).setProxy(bean); 
       } 
      } catch (Exception e) { 
       // ignore 
      } 
     } 
     return bean; 
    } 

    @Override 
    public int getOrder() { 
     return Ordered.LOWEST_PRECEDENCE; 
    } 
} 

它是醜陋的,但工作。

+0

Ooooh。好吃。我喜歡它@Biju的外觀。讓我試試看...... – Gray 2012-07-16 19:43:14

+0

我最終刪除了'Ordered',因爲它出於某種原因似乎對我的AOP有不利影響。但否則它正在工作。也許你應該刪除'Ordered'?再次感謝。 – Gray 2012-07-17 21:05:00

2

有Spring提供一個方便的靜態實用AopContext.currentProxy()方法返回一個代理對象從它被調用。

雖然使用它被認爲是一種不好的做法,語義同樣的方法在Java EE的存在,以及:SessionContext.getBusinessObject()

我寫了幾篇關於這種實用方法和各種陷阱的文章:12,3

+0

我開始說我在撥打電話時沒有加入代理,所以目前沒有代理。但是我沒有理由不能將getPager()方法標記爲「@ Transactional」,在這種情況下我會這樣做。所以這是有益的@Tomasz。謝謝! – Gray 2012-07-19 16:14:54

2

使用Spring注入一個bean引用到bean,甚至同一個bean,就像你對任何其他bean的引用。不需要採取特殊行動。

這種可變的存在明確地確認在類設計該類期望以某種方式被代理。這不一定是壞事,因爲aop可以改變違反班級合同的行爲。

bean引用通常用於一個接口,並且該接口甚至可以是用於自引用內部方法的不同接口。

保持簡單。那種方式就是瘋狂。 :-)

更重要的是,確保語義有意義。需要做到這一點可能是一種代碼味道,該類混合在多個職責中,最好分解爲單獨的bean。

+0

謝謝Kent。我希望不必爲我的所有DAO做這樣的注入。 'BeanPostProcessor'似乎正在工作,但我會牢記這一點。 – Gray 2012-08-14 14:23:09