我遇到了一个奇怪的问题,我很难追踪。 我有一个类(ServiceErrorInterceptor)定义为一个@Aspect
它通过XML配置实例化为单例bean。 XML 配置允许我注入其依赖的 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 {
...
...
}
我已经查看了日志(我启用了 spring 跟踪日志),但没有看到任何突出的内容。 在这里发布整个日志可能是矫枉过正的。 如果日志的特定部分有价值,请告诉我,我会发布它。
如果有帮助,我可以发布我的代码方面、我的 junit 和我的配置。
应用程序上下文.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 将构造两次。
- 然而,奇怪的是,对于@Component和@Aspect注释以及XML配置,构造函数仍然只被调用两次。
那么,为什么同时使用 XML 配置和@Aspect注释会导致构造函数使用两个不同的 Bean ID 调用两次呢?
我已经进一步验证了,如果我将整个AOP定义移动到XML配置中(删除@Aspect和@Pointcut注释),那么Bean只构造一次。
结束编辑
谢谢
埃里克
@Aspect之外,您的方面是否有任何自动检测注释(@Component、@Service)等 - 如果是这样,这可能是为什么似乎存在不同的 Bean 以及您的配置中定义的 Bean 的原因之一。
此外,只需扫描所有配置,以确保您没有在其他地方声明此 Bean。
据我所知,在Junit级别没有什么特别需要做的。
在 SpringSource STS 论坛上与人们进行了大量讨论(请参阅此线程)之后,事实证明该问题与 AJDT 配置有关。 目前,AJ 正在编织方面,Spring 正在类路径上定位方面,因此它们都在执行。
不幸的是,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>
感谢 STS 论坛上的 Andy Clement 提供此发现和解决方法。 他将提出 JIRA 问题,以进一步解决 maven 插件中的这一缺点。
您可能会发现自己处于同样情况的一种可能方式:您使用了 new 运算符,而不是让 Spring 注入您的服务。
请记住,我们不是在AspectJ编译时编织这里。不,我们使用的是 Spring AOP 代理,因此 Spring 必须实例化对象并用代理对其进行修饰。如果你像我一样愚蠢,并在测试中创建了一个新服务,你将不会得到任何AOP。
更有理由使用 AspectJ 进行编译时编织,并跳过 Spring AOP 的所有缺点,例如运行时编织启动延迟、无法编织非公共和非最终类。