我目前正在將我的一個項目窗體「自我配置的彈簧」遷移到彈簧啓動。而大多數的東西已經工作,我有一個@Transactional
方法的問題,當它被稱爲上下文不存在以前設置由於調用「目標」實例,而不是「代理」實例(我會試着在下面詳細說明)。@Transactional方法調用目標不在代理實例
首先我的類層次結構的精簡視圖:
@Entity public class Config { // fields and stuff } public interface Exporter { int startExport() throws ExporterException; void setConfig(Config config); } public abstract class ExporterImpl implements Exporter { protected Config config; @Override public final void setConfig(Config config) { this.config = config; // this.config is a valid config instance here } @Override @Transactional(readOnly = true) public int startExport() throws ExporterException { // this.config is NULL here } // other methods including abstract one for subclass } @Scope("prototype") @Service("cars2Exporter") public class Cars2ExporterImpl extends ExporterImpl { // override abstract methods and some other // not touching startExport() } // there are other implementations of ExporterImpl too // in all implementations the problem occurs
調用的代碼是這樣的:
@Inject private Provider<Exporter> cars2Exporter; public void scheduleExport(Config config) { Exporter exporter = cars2Exporter.get(); exporter.setConfig(config); exporter.startExport(); // actually I'm wrapping it here in a class implementing runnable // and put it in the queue of a `TaskExecutor` but the issue happens // on direct call too. :( }
到底是什麼問題?
在startExport()
的調用中,ExporterImpl
的字段config
爲空,儘管它已被設置在之前。
我到目前爲止發現的: 在exporter.startExport();
的斷點處,我檢查了eclipse調試器顯示的導出器實例的id。在寫作這篇文章的debbug回合中,它是16585
。繼續執行到startExport()
的呼叫/第一行,我再次檢查了id(這次是this
),期望它是相同的,但是意識到它不是。這裏是16606
......所以對startExport()
的調用是在該類的另一個實例上完成的...在之前的一輪調試中,我檢查了哪個實例/編號爲setConfig()
的調用將進行到第一個調用(16585在這種情況下)。這解釋了爲什麼配置字段在16606實例中爲空。
爲了理解在我打電話給exporter.startExport();
的行與實際的第一行startExport()
之間發生了什麼,我點擊了eclipse調試器中這兩行之間的步驟。
在那裏,我來到line 655 in CglibAopProxy看起來像這樣:
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
這裏檢查的論點我發現proxy
是ID爲16585和target
一個與16606.
可惜我實例沒有深入到彈簧aop的東西,知道這是如何應該是...
我只是想知道爲什麼有兩個實例調用不同的方法。呼叫setConfig()
去代理實例和呼叫做startExport()
到達目標實例,因此無法訪問以前設置的配置...
如上所述,項目已遷移到春季啓動,但我們在哪裏之前已經在使用Athens-RELEASE
版本的彈簧平臺。從我可以告訴的是,在遷移之前沒有特殊的AOP配置,遷移後沒有明確設置值。
得到這個問題固定的(或至少以某種方式工作)我已經嘗試過許多東西:
- 從子類
- 移動@Transactional從方法層面類
- 覆蓋刪除@Scope子類中的startExport()並將@Transactional放在這裏
- 將@EnableAspectJAutoProxy添加到應用程序類(我甚至無法登錄 - 無錯誤消息)
- set spring.aop.proxy-tar獲得一流的,以不同勢組合上面真正
- ...
我目前就如何得到這個工作回來的線索......
在此先感謝
*希望有人可以幫助*
如果你不直接調用該字段,但getConfig()會發生什麼? –
'getConfig()'在與'startExport()'相同的實例上被調用並返回null。 – Dodge
刪除'setConfig'上的'final'關鍵字。代理被創建,但它是一個基於類的代理。導致在代理上調用'setConfig'並在代理實例上調用'startExport'。或者將'spring.aop.proxy-target-class'切換到'false'來使用基於接口的代理。 –