2012-04-12 97 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的所有缺陷,如运行时编织启动延迟,无法编织非公共类和非最终类。