spring - Spring AOP 的 IllegalArgumentException
问题描述
此问题首次报告为Spring issue #24248。
我正在使用 Spring AOP 构建一个应用程序,并且正在使用方面来修改我的一些业务对象。当我启动我的应用程序时,我得到以下堆栈跟踪(仅显示根):
java.lang.IllegalArgumentException: methods with same signature get() but incompatible return types: [interface main.DomainObjectInterfaceA, interface main.DomainObjectInterfaceB]
at sun.misc.ProxyGenerator.checkReturnTypes(ProxyGenerator.java:712)
at sun.misc.ProxyGenerator.generateClassFile(ProxyGenerator.java:461)
at sun.misc.ProxyGenerator.generateProxyClass(ProxyGenerator.java:339)
at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:639)
at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:557)
at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230)
at java.lang.reflect.WeakCache.get(WeakCache.java:127)
at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:419)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:719)
at org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:123)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:473)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:355)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:304)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:439)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1712)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:581)
... 10 more
我从我的应用程序中提取了一个最小的代码片段来重现这个堆栈跟踪。
kriegaex 的评论:我创建了一个MCVE并将其推送到GitHub存储库。
我的域模型由三个类组成:
package main;
public interface DomainObjectInterfaceA {
}
package main;
public interface DomainObjectInterfaceB{
}
package main;
public class DomainObjectImplementation implements DomainObjectInterfaceA, DomainObjectInterfaceB {
private int fieldToModifyThroughAspect = 0;
public int getFieldToModifyThroughAspect() {
return fieldToModifyThroughAspect;
}
public void setFieldToModifyThroughAspect( int aFieldToModify ) {
fieldToModifyThroughAspect = aFieldToModify;
}
}
此外,我有以下两个 Spring 组件:
package main;
@Component
public class ComponentImplementation implements ComponentInterfaceA<DomainObjectImplementation>, ComponentInterfaceB<DomainObjectImplementation> {
public DomainObjectImplementation get() {
return new DomainObjectImplementation();
}
}
package main;
@org.aspectj.lang.annotation.Aspect
@Component
public class Aspect {
@Pointcut( "execution(public DomainObjectImplementation main.ComponentImplementation.*(..))" )
public void anyPublicOperation() {
}
@AfterReturning( pointcut = "anyPublicOperation()", returning = "aObject" )
public Object get( Object aObject ) {
DomainObjectImplementation returningObject = ( DomainObjectImplementation ) aObject;
returningObject.setFieldToModifyThroughAspect( 5);
return returningObject;
}
}
重现问题的关键部分是以下两个通用接口,它们由以下人员实现ComponentImplementation
:
package main;
public interface ComponentInterfaceA<T extends DomainObjectInterfaceA> {
T get();
}
package main;
public interface ComponentInterfaceB<T extends DomainObjectInterfaceB> {
T get();
}
以上两个接口共享一个签名相同但泛型类型不同的方法。ComponentImplementation
使用满足这两个通用参数的类来实现这两个接口。
最后两个必需的类当然是下面声明的Main
类和Spring
配置类:
package main;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan( basePackageClasses = Config.class )
public class Config {
}
package main;
public class Main {
public static void main( String[] args ) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( Config.class );
ComponentImplementation bean = context.getBean( ComponentImplementation.class );
DomainObjectImplementation domainObject = bean.get();
System.err.println("Aspect modified get method = " + ( domainObject.getFieldToModifyThroughAspect() == 5));
}
}
我也尝试使用 进行配置EnableAspectJAutoProxy
,proxyTargetClass = true
但随后抛出相同的异常,堆栈跟踪略有不同(即 JDK 代理与 Cglib)
完整的依赖列表:
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aspectj/aspectjrt -->
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
</dependencies>
解决方案
推荐阅读
- .net - Azure AD:Web api 调用另一个 Web api。授权类型错误
- mongodb - MongoDB 的 updateMany() 和重复 updateOne() 在性能方面有什么区别?
- android - Cordova (android) : 避免闪屏前的灰色背景
- python - 只返回一个字符串而不是两个几乎相同的字符串
- parsing - 双递归函数中的Haskell类型错误
- flutter - MultipartRequest 成功上传到 s3,但数据似乎无效
- github-actions - Github action 可选步骤执行
- amazon-web-services - 无法在 EMR CAWS 集群中的主节点上进行 SSH
- r - 计算数据框中事件的实例
- c# - 需要帮助编辑 CSV 文件中的字段?