2012-04-12 43 views
2

我遇到了一個奇怪的問題,我很難追查到。我有一個類(ServiceErrorInterceptor)定義爲@Aspect,它通過XML配置實例化爲單例bean。 XML配置允許我注入它的依賴bean。JUnit編織錯誤Spring AOP Bean

在我的正常工作流程中,一切正常。方面類正確實例化,每當調用通知時,注入的bean就像我所期望的那樣。

但是,當我運行我的JUnit測試時,所有注入的bean都是空的。這使我得出這樣的結論,即建議是從一個不同的bean調用的,而不是由Spring實例化的單一bean。爲了進一步驗證我的假設,我在實例化過程中調用的setter上放置了一個斷點,並且如果我在我的建議中放置了斷點,請參閱bean id與bean id不同。

是否有一些特殊的配置,我必須在我的JUnit類中啓用才能解決這個問題?我的測試類已經被標註有:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { 
     "classpath:spring/applicationContext-base.xml", 
     "classpath:spring/applicationContext-calculateServices.xml", 
     "classpath:spring/applicationContext-dom.xml"}) 
public class LendingSimulationServiceImplTest { 
... 
... 
} 

我已經通過日誌看(我啓用了春天跟蹤日誌),但沒有看到任何脫穎而出。在這裏發佈整個日誌可能會過度。如果在日誌的特定部分有價值,請讓我知道,我會發布它。

我能夠發佈我的代碼的方面,我的junit和我的配置,如果這是有幫助的。

應用context.xml的片段:

<!-- SPRING ASPECT BEAN. POINTCUT DEFINED IN BEAN WITH ANNOTATION --> 
<bean id="serviceErrorInterceptor" class="com.cws.cs.lendingsimulationservice.error.ServiceErrorInterceptor" scope="singleton"> 
    <property name="errorMessageProvider" ref="resourceBundleProviderImpl"/> 
    <property name="defaultLocale"> 
     <util:constant static-field="java.util.Locale.ENGLISH" /> 
    </property> 
</bean> 

任何建議,將不勝感激。

編輯

我的bean被實現爲:

@Aspect 
public class ServiceErrorInterceptor { 

    /** 
    * Logger 
    */ 
    private static final Logger logger = LoggerFactory.getLogger(ServiceErrorInterceptor.class); 

    /** 
    * SOAP Header data 
    */ 
    @Autowired 
    private SOAPHeaderData soapHeaderData; 

    public ServiceErrorInterceptor(){ 
     int x = 0; 
     x=x+1; 

    } 

    /** 
    * Exception Interceptor. 
    * @param ex 
    */ 
    @AfterThrowing(pointcut = "execution(* com.cws.cs.lendingsimulationservice.process.CalculatorProcess.calculate (..))", throwing = "ex") 
    public void errorInterceptor(Exception ex) { 
     if (logger.isDebugEnabled()) { 
      logger.debug("Error Message Interceptor started"); 
     } 

    } 

我的聚甲醛的相關部分:

<!-- Aspect Oriented Programming (AOP) Framework (depends on spring-core, 
     spring-beans) Define this if you use Spring AOP APIs (org.springframework.aop.*) --> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-aop</artifactId> 
     <version>${org.springframework.version}</version> 
    </dependency> 

    <!-- Support for AspectJ Annotations --> 
    <dependency> 
     <groupId>org.aspectj</groupId> 
     <artifactId>aspectjweaver</artifactId> 
     <version>${org.aspectj}</version> 
    </dependency> 

我已經做了進一步的調試,並把一個斷點在假構造函數,我得到如下結果:

  • 使用@Aspect和XML配置,構造函數被調用兩次(不同的bean ID)
  • 如果我刪除@Aspect註釋,那麼它只被調用一次。
  • 如果離開@Aspect但刪除XML配置,則甚至不會調用構造函數。
  • 如果我將@Component註釋與@Aspect結合使用(但沒有任何XML配置),那麼這個bean會被構造兩次。
  • 然而,奇怪的是,對於XML配置@Component和@Aspect註釋,構造函數仍然只調用兩次。

那麼爲什麼要同時使用XML配置和@Aspect註釋會導致構造函數被兩次不同的bean ID調用兩次?

我進一步驗證,如果我將整個AOP定義移動到XML配置中(移除@Aspect和@Pointcut註釋),那麼這個bean只構造一次。

編輯完

感謝,

埃裏克

回答

1

在SpringSource STS論壇上與人們進行了很多討論後(見this thread),結果發現問題與AJDT配置有關。目前,AJ正在編寫這方面的知識,而Spring正在將該方面定位到Classpath上,因此它們都被執行。

不幸的是,AJ Maven插件缺少一個配置參數以允許排除編織;當前的配置不包括LTW和CTW。

因此,目前的解決方法是將-xmlConfigured添加到AJ編譯器標誌中,然後在aop.xml管理中指定aop.xml文件,該文件僅列出要包含在項目中的AJ方面。

爲了得到這個工作,加上「-xmlConfigured」的項目屬性 「非標準編譯器選項」,然後在AspectJBuild一個簡單的aop.xml文件文件>'aop.xml文件 管理的角度它:

<aspectj> 
    <aspects> 
     <aspect name="com.fooMyNewNoneSpringAspect"/> 
    </aspects> 
</aspectj> 

感謝Andy克萊門特在STS論壇這一發現和解決方法。他將提高JIRA問題以進一步解決maven插件中的這個缺點。

1

是否任何機會的方面有任何的自動檢測註解(@Component,@Service)等,除了@Aspect - 如果它的確如此,這可能是爲什麼不同的bean似乎與您在配置中定義的bean一起出現的原因之一。

此外,只需掃描所有配置,以確保您沒有在別處聲明此bean。

在我意識到的Junit級別上沒有什麼特別的事情需要完成。

+0

不可以。唯一的註釋是@Aspect。另外,如果有一個額外的bean,它將在Spring日誌中顯示爲一個重複的bean定義。日誌中沒有任何東西。我只是意識到我正在使用AspectJ以及其他方面編織其他類的其他方面,但我不知道如何或爲什麼會影響任何東西。 – 2012-04-13 01:05:05

+0

您是否可以確認您在Spring AOP中使用了@Aspect註釋,而不是使用AspectJ編譯時間或加載時間織入,如果是編譯時或加載時編織,那麼注入到某個方面的依賴關係有點不同:使用aspectOf工廠方法 - http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html – 2012-04-13 13:45:20

+0

我在Spring AOP中使用@Aspect註釋。我添加了一些AspectJ編織的其他方面,但已經從pom和包中刪除它們。去除AJ沒有任何區別。我用更多的信息編輯了我的問題。謝謝! – 2012-04-13 15:46:55

0

你可能會發現自己在同樣的情況一種可能的方法:你使用的運營商,而不是讓春注入您服務。

請記住,我們不在AspectJ編譯時編織在這裏。不,我們使用Spring AOP代理,所以Spring必須實例化對象並用代理對它進行打扮。如果你像我一樣愚蠢,並且在你的測試中創建了一項新服務,你將不會得到任何AOP。

所有更多的理由使用AspectJ進行編譯時編織,跳過Spring AOP的所有缺陷,如運行時編織啓動延遲,無法編織非公共類和非最終類。