Spring AOP at Service Layer

13,753

Solution 1

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

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 has decided to use a J2SE proxy (com.sun.proxy.$Proxy57) probably because CrudService implements an interface. To force the use of CGLIB you can tweak your XML:

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

Solution 2

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

@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.

Thanks a lot for your time.

Share:
13,753
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin almost 2 years

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


    @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

    <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: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:

    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.

    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.

  • Admin
    Admin over 10 years
    Hi @samlewis, thank you for your time. Actually I read that before, but when I put 'proxy-target-class' I get another exception: Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy54]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy54 But none of them is marked with final or non-visible. I changed the Repository to be public. I don't no what's going on. Thanks.
  • Admin
    Admin over 10 years
    (*I don't know) When I leave Repository with default access modifier I get this exception: Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.xpto.user.service.$Proxy54]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.xpto.user.service.$Proxy54 I think that exception happens because of default access of UserRepository interface. Thanks