Spring AOP代理未按预期工作

7

实际上,我对Spring代理的行为感到困惑。我认为我知道J2EE,cglib和AspectJ代理机制之间的主要区别。在我的配置类中启用了AspectJ自动代理,并且将AspectJ包含在类路径中。

我的配置如下:

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ApplicationConfiguration {
    ...
}

AspectJ 依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.5</version>
</dependency>

通过使用这个简单的设置,我假定Bean注入按预期工作。但是,我的应用程序却出现了"IllegalArgumentException"异常,消息显示为“无法将[...]字段[...]设置为com.sun.proxy.$Proxy30”。这意味着Spring在我的服务中使用J2EE代理,即使启用了AspectJ代理。
最后,我发现我的服务上的接口导致了这种行为。似乎Spring决定在我的服务实现任何接口时使用J2EE代理。如果我删除它们,就可以正常运行。
失败:
@Service
@Validated
public class MyService implements Interface1, Interface2 {

    @override
    public void methodFromInterface1() {
    }

    @override
    public void methodFromInterface2() {
    }

    public void serviceMethod() {
    }
}

好的:

@Service
@Validated
public class MyService {

    public void methodFromInterface1() {
    }

    public void methodFromInterface2() {
    }

    public void serviceMethod() {
    }
}

直到现在,我了解到j2ee代理需要接口。但是对于实现接口的bean而言,cglib/aspectj代理对我来说是新的概念。
是否有一种方法...
... 强制Spring不使用j2ee代理?
... 强制Spring使用cglib/aspectj代理(即使对于具有接口的类)?
这是Spring的一个bug还是期望的行为?
编辑:示例已更新,@Transactional被@Validated替换。
编辑2:解决方案:@Validated受MethodValidationPostProcessor影响。因此,此bean的proxyTargetClass属性必须设置为true。
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    final MethodValidationPostProcessor methodValidationPostProcessor;
    methodValidationPostProcessor = new MethodValidationPostProcessor();
    methodValidationPostProcessor.setProxyTargetClass(true);
    return methodValidationPostProcessor;
}
1个回答

2
"@EnableAspectJAutoProxy" 注解适用于 "@Aspect" 注解,而不是 "@Transactional" 注解。为了实现这一点,您需要在 "@Configuration" 类上使用 "@EnableTransactionManagement" 注解,并设置 "proxyTargetClass = true" 属性值。"
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@EnableTransactionManagement(proxyTargetClass = true)
public class ApplicationConfiguration {
    ...
}

你说得对。我也在第二个配置类上配置了<code>@EnableTransactionManagement</code>,但没有使用<code>proxyTargetClass = true</code>,出乎意料的是它也能正常工作。请注意这只是一个例子,问题同样会在服务类上使用<code>@Validated</code>时出现。 - baymon
@baymon 没错。所以,你必须在那个注解中设置 proxyTargetClass = true,使Spring对于带有 @Transactional 注解的类使用CGLib代理。 - Rohit Jain
1
实际上,如果您不使用Spring AOP,则甚至不需要@EnableAspectJAutoProxy注解。要在事务上启用aspectj代理,可以使用@EnableTransactionManagement注解的mode属性。 - Rohit Jain
我通过比较我的两个项目来分析所描述的行为。我的当前项目不使用数据库,但我想使用基于代理的bean验证... 我已经修改了我的示例,停止关注 @Transactional :) ... 我使用 @Validated 在我的服务类上出现问题。对于造成的困惑,我很抱歉! - baymon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接