JUnit编织错误的Spring AOP Bean

时间:2012-04-12 18:53:49

标签: java spring junit aop

我遇到了一个奇怪的问题,我很难跟踪。我有一个类(ServiceErrorInterceptor)定义为@Aspect,它通过XML配置实例化为单例bean。 XML配置允许我注入其依赖bean。

在我的正常工作流程中,一切正常。方面类被正确地实例化,并且每当调用通知时,注入的bean就像我期望的那样。

但是,当我运行JUnit测试时,我注入的所有bean都是null。这使我得出结论,建议是从一个不同的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和我的配置。

application-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");
        }

    }

我的pom的相关部分:

    <!-- 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将被构造两次。
  • 然而,奇怪的是,对于@Component和@Aspect注释 AND XML配置,构造函数仍然只被调用两次。

那么为什么同时使用XML配置和@Aspect注释会导致构造函数被两个不同的bean ID调用两次?

我进一步验证了如果我将整个AOP定义移动到XML配置中(删除@Aspect和@Pointcut注释),那么bean只构造一次。

结束编辑

谢谢,

埃里克

3 个答案:

答案 0 :(得分:1)

除了@Aspect之外,你的方面是否有任何自动检测注释(@ Component,@ service)等 - 如果确实如此,这可能是为什么一个不同的bean似乎与一个一起存在的一个原因在您的配置中定义。

此外,只需扫描所有配置,确保您没有在其他位置声明此bean。

我所知道的Junit级别没有什么特别需要做的事。

答案 1 :(得分:1)

经过与SpringSource STS论坛(见this thread)的大量讨论,结果证明该问题与AJDT配置有关。目前,AJ正在编织这个方面,而Spring正在将这个方面定位在Classpath上,因此它们都被执行了。

不幸的是,AJ maven插件缺少配置参数以允许排除编织;目前的配置不包括LTW和CTW。

因此,目前的解决方法是将-xmlConfigured添加到AJ编译器标志中,然后在aop.xml管理中指定aop.xml文件,该文件仅列出要包含在项目中的AJ方面

  

要使其生效,请将“-xmlConfigured”添加到“项目属性”中   '非标准编译器选项'然后在AspectJBuild&gt;'aop.xml中   管理'将其指向一个简单的aop.xml文件:

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

感谢Andy Clement在STS论坛上的发现和解决方法。他将提出JIRA问题,以进一步解决maven插件中的这个缺点。

答案 2 :(得分:0)

您可能会发现自己处于相同情况的可能方式:您使用运算符,而不是让Spring 注入您的服务。

请记住,我们不是在AspectJ编译时编织的。不,我们正在使用Spring AOP代理,所以Spring必须实例化对象并用代理服饰。如果你像我一样愚蠢,并在你的测试中创建了一个新的服务,你就不会获得任何AOP。

使用AspectJ进行编译时编织的更多理由,并跳过Spring AOP的所有缺点,例如运行时编织启动延迟,无法编织非公共和非最终类。