Aspect Advice for Spring Data Repository doesnt work

半城伤御伤魂 提交于 2019-12-05 07:04:35

问题


im trying to create some pointcuts and before advices for Repositories in order to enable filtering over entitymanager for some Repositories in Spring Data in Spring Boot. i also have web and service layer in project and AspectLogging works for both. But i couldnt do same for repositories. i have been struggling for 2 days and i tried so many things for fix it. i read almost every docs, issues and threads about this( proxy issues CGlib and JDK Proxy etc). i used jhipster for creating project.

i cant deploy Application except @Pointcut with CrudRepository. and even its deployed @Before isnt called for a method call in Repository. i think i have a similar Problem like in following question. proxy confusion

    Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xxx.zzz.business.repository.ApplyRepository com.xxx.zzz.web.rest.applyResource.ApplyRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applyRepository': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy173]: 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.$Proxy173
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:561)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
    ... 61 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applyRepository': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy173]: 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.$Proxy173
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:116)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1523)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:314)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1120)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1044)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
    ... 63 more
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy173]: 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.$Proxy173
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:212)
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:109)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:447)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:333)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:293)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1719)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:113)
    ... 70 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy173
    at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
    at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
    at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
    at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
    at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:56)
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:202)
    ... 77 more

Does anyone know what its could be ?

Classes and Configs look like following.

Repository:

public interface ApplyRepository extends JpaRepository<Apply,Long>,QueryDslPredicateExecutor<Apply> {

public Page<Apply> findAll(Predicate predicate, Pageable p); 
}
...
}

Database Config:

@Configuration
@EnableJpaRepositories("com.xxx.zzz.business.repository")
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
@EnableTransactionManagement//(proxyTargetClass = false)
public class DatabaseConfiguration  {
....

AspectJ Config:

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
// @EnableLoadTimeWeaving(aspectjWeaving = ...     )
public class LoggingAspectConfiguration {
...

System Architecture:

@Aspect
public class SystemArchitecture {

/**
 * A join point is in the web layer if the method is defined
 * in a type in the com.xyz.someapp.web package or any sub-package
 * under that.W
 */
@Pointcut("within(com.xxx.zzz.web.rest..*)")
public void inWebLayer() {
}

/**
 * A join point is in the service layer if the method is defined
 * in a type in the com.xyz.someapp.service package or any sub-package
 * under that.
 */
@Pointcut("within(com.xxx.zzz.business.service..*)")
public void inServiceLayer() {
}

/**
 * A join point is in the data access layer if the method is defined
 * in a type in the com.xyz.someapp.dao package or any sub-package
 * under that.
 */
@Pointcut("within(com.xxx.zzz.business.repository..*)")
public void inDataAccessLayer() {
}



/**
 *  All layers
 */
@Pointcut("inWebLayer() || inServiceLayer() || inDataAccessLayer()")
public void inALL(){
}



 @Pointcut("within(org.springframework.data.repository.CrudRepository)")
    //@Pointcut("execution(*org.springframework.data.repository.Repository+.*               (..))")
    //@Pointcut("execution(* com.xxx.zzz.business.repository+.*(..))")
    //@Pointcut("execution(* org.springframework.data.jpa.repository.JpaRepository+.*(..))")
     //@Pointcut("execution(*        com.xxx.zzz.business.repository.ApplyRepository.*(..))")
    public void inDATAExec(){}

}

FilterAspect:

@Aspect
@Transactional
public class FilterAspect {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @PersistenceContext
    private EntityManager entitymanager;

    @Before("com.xxx.zzz.aop.logging.SystemArchitecture.inDATAExec())") //  "execution(* com.xxx.zzz.business.repository.InvoiceRepository.*(..))"
    public void doAccessCheck() {
        if (TransactionSynchronizationManager.isActualTransactionActive() && SecurityUtils.isAuthenticated()) {
            Session session = entitymanager.unwrap(Session.class);
            session.enableFilter("GLOBAL_FILTER").setParameter("customerId", SecurityUtils.getCurrentCustomerId());
        }
    }

EDIT: i solved problem. it was related somehow to wrong pointscuts and names. i tried to change pointcuts for custom annotation in Repository. it doesnt work for method or class level. i read in following links issues about this. advice 1 advice 2 im struggling for hours for target and annotation. but no result. is it really imposible to add custom annotations in Spring Data Repositories for advicing ?

Annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
//@Inherited
public @interface CustomerRequired {
    String value() default "customerrequired";
}

Repository:

public interface InvoiceRepository extends JpaRepository<Invoice,String>, QueryDslPredicateExecutor<Invoice> {

    @CustomerRequired
    public Page<Invoice> findAll(Predicate predicate, Pageable p);

     ...
}

Pointcut and Advice:

@Pointcut(value = "@target(customerRequired)",argNames = "customerRequired")
    public void targetCustomer(@SuppressWarnings("unused") CustomerRequired customerRequired) {/**/}


@Before(value = "com.xxx.zzz.aop.logging.SystemArchitecture.targetCustomer(customerRequired) && com.xxx.zzz.aop.logging.SystemArchitecture.inDataLayer()")
public void doAccessCheck(JoinPoint joinPoint, CustomerRequired customerRequired) {
    if (TransactionSynchronizationManager.isActualTransactionActive() && SecurityUtils.isAuthenticated()) {
        Session session = entitymanager.unwrap(Session.class);
        session.enableFilter("GLOBAL_FILTER").setParameter("customerId", SecurityUtils.getCurrentCustomerId());
    }
}

回答1:


Instead of using

@Pointcut("within(org.springframework.data.repository.CrudRepository)")
public void inDATAExec(){}

use like following

@Pointcut("this(org.springframework.data.repository.Repository)")
public void inDATAExec(){}

and what it does is

any join point (method execution only in Spring AOP) where the 
proxy implements the Repository interface

You can have a look it at http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html

Hope it helps!



来源:https://stackoverflow.com/questions/34332046/aspect-advice-for-spring-data-repository-doesnt-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!