Java 服务层的Spring AOP

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18369258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:56:16  来源:igfitidea点击:

Spring AOP at Service Layer

javaspring-mvcproxyaopspring-aop

提问by Celso Marques

I need some help with Spring AOP. I've the following code:

我需要一些有关 Spring AOP 的帮助。我有以下代码:



@Service
public class UserSecurityService implements UserDetailsService {

    @Autowired
    private UserService userService;
    ....
}


@Service
public class UserService extends CrudService<User, UserRepository> {

    public UserService() {
        super();
    }

    @Autowired
    public UserService(UserRepository repository) {
        super(repository);
        this.repository = repository;
    }
    ....
}


@Repository
interface UserRepository extends JpaRepository<User, String> {
     ...
}


application-context.xml

应用程序上下文.xml

<import resource="classpath*:spring/application-context-db.xml" />
<import resource="classpath*:spring/application-context-aop.xml" />
<import resource="classpath*:spring/application-context-mail.xml" />
<import resource="application-context-security.xml" />

<context:component-scan base-package="com.xpto">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" />
</context:component-scan>


application-context-aop.xml

应用程序上下文aop.xml

<aop:aspectj-autoproxy />
<aop:config>
    <aop:aspect id="serviceLoggingAspect" ref="serviceLoggingAspectBean">
        <aop:pointcut id="servicePointcut"
                expression="@within(org.springframework.stereotype.Service)" />

        <aop:before method="before" pointcut-ref="servicePointcut" />
        <aop:after-returning method="afterReturning" pointcut-ref="servicePointcut" returning="result" />
        <aop:after-throwing method="afterThrowing" pointcut-ref="servicePointcut" throwing="exception" />
    </aop:aspect>
</aop:config>


When I try to load my application at Tomcat, I get the following exception:

当我尝试在 Tomcat 上加载我的应用程序时,出现以下异常:

Caused by: java.lang.IllegalArgumentException: Can not set com.xpto.user.service.UserService field com.xpto.user.security.service.UserSecurityService.userService to com.sun.proxy.$Proxy57
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:680)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:510)
... 35 more


I've the same configuration at Web layer to Logging my application and it works fine, but when I put AOP at Service layer I get this exception.

我在 Web 层有相同的配置来记录我的应用程序,它工作正常,但是当我将 AOP 放在服务层时,我得到了这个异常。

I'm using Spring MVC and at web.xml I configured to load two different contexts, one loads only @Controller and the other loads @Repository and @Service.

我正在使用 Spring MVC 并且在 web.xml 中我配置为加载两个不同的上下文,一个只加载@Controller,另一个加载@Repository 和@Service。

采纳答案by samlewis

You are not injecting an interface so you need to use CGLIB proxies, the spring reference manualstates:

您没有注入接口,因此您需要使用 CGLIB 代理,spring 参考手册指出:

Spring AOP defaults to using standard J2SE dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.

Spring AOP can also use CGLIB proxies. This is necessary to proxy classes, rather than interfaces. CGLIB is used by default if a business object does not implement an interface. As it is good practice to program to interfaces rather than classes, business classes normally will implement one or more business interfaces.

Spring AOP 默认为 AOP 代理使用标准的 J2SE 动态代理。这允许代理任何接口(或接口集)。

Spring AOP 也可以使用 CGLIB 代理。这是代理类而不是接口所必需的。如果业务对象未实现接口,则默认使用 CGLIB。由于编程接口而不是类是一种很好的做法,因此业务类通常会实现一个或多个业务接口。

Spring has decided to use a J2SE proxy (com.sun.proxy.$Proxy57) probably because CrudServiceimplements an interface. To force the use of CGLIB you can tweak your XML:

Spring 决定使用 J2SE 代理 ( com.sun.proxy.$Proxy57) 可能是因为CrudService实现了一个接口。要强制使用 CGLIB,您可以调整您的 XML:

<aop:aspectj-autoproxy proxy-target-class="true"/>

回答by Celso Marques

Spring has decided to use a J2SE proxy (com.sun.proxy.$Proxy57) probably because CrudService implements an interface.

Spring 决定使用 J2SE 代理 (com.sun.proxy.$Proxy57) 可能是因为 CrudService 实现了一个接口。

@samlewis: This sentence that you wrote pushed me to create interfaces to my Services and when I did that, LoggingAspect worked really fine. So, I'm not using proxy-target-class=true.

@samlewis:你写的这句话促使我为我的服务创建接口,当我这样做时,LoggingAspect 工作得非常好。所以,我没有使用proxy-target-class=true

Thanks a lot for your time.

非常感谢您的时间。