spring切点表达式提取jdk版本与aspectjweaver版本不匹配

在使用Spring AOP时,通过注解定义切点表达式出现编译错误'0can't find referenced pointcut pointcut'。该问题与JDK版本11和aspectjweaver依赖包版本有关。将aspectjweaver版本更新到1.9.6后,问题得到解决,确保了注解配置的正确运行。

0 can’t find referenced pointcut pointcut

spring AOP同样的代码,xml配置可以测试通过,注解抽取切点表达式后测试编译报错0 can’t find referenced pointcut pointcut
找了一下,是依赖包版本问题
用的是jdk11,把aspectjweaver的版本改为1.9.6之后就不报错了

  <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>
<think>嗯,用户问的是Spring AOP切点表达式应该写接口还是实现类。我需要先回忆一下Spring AOP的工作原理。记得Spring AOP是基于代理的,如果是JDK动态代理的话,代理对象会实现接口,而CGLIB代理则是通过继承目标类来实现的。所以这可能影响到切点表达式的写法。 接下来,用户可能想知道在定义切点的时候,应该针对接口的方法还是实现类的方法。比如,如果有一个UserService接口和其实现类UserServiceImpl,切点是应该写在接口的方法上还是实现类的方法上? 这时候需要考虑AOP的匹配规则。Spring AOP在匹配方法时,默认是基于运行时代理对象的,也就是说,使用JDK代理时,只能拦截接口中声明的方法;而用CGLIB的话,可以拦截具体类中的方法,包括那些在接口中的方法。 然后,切点表达式中的execution表达式,如果是写接口的方法,比如execution(* com.example.UserService.*(..)),那么管代理方式如何,只要方法在接口中声明,就会被拦截。而如果写实现类的方法,比如execution(* com.example.UserServiceImpl.*(..)),那么当使用JDK代理时,可能无法拦截,因为代理对象是接口类型,而是实现类类型。 过,Spring AOP在匹配时,是否会自动考虑到实现类的方法呢?可能需要更仔细的分析。比如,当使用execution表达式时,如果目标对象的方法确实被调用,管代理方式如何,execution表达式中的类名如果是实现类的话,是否能正确匹配? 另外,用户可能在实际使用中遇到了切面生效的问题,想知道是是因为切点表达式写错了地方。比如,他们可能把切点写在接口上,但实际调用的方法是在实现类中新增的,这时候用接口的切点表达式就无法拦截到。 可能还需要提到@target和within这些指示符的区别。比如,使用within(com.example.UserServiceImpl)会匹配在UserServiceImpl类内部执行的方法,而使用target(com.example.UserServiceImpl)则会匹配代理目标对象是该类的情况。 总结一下,应该建议用户根据具体情况选择。如果希望拦截接口中定义的所有方法,就写接口;如果需要拦截实现类特有的方法,或者通过接口调用的情况,应该写实现类。同时,要注意代理方式的影响,JDK代理只能基于接口,而CGLIB可以基于类。因此,在定义切点表达式时,明确目标方法的声明位置和代理方式是很重要的。 另外,可能还需要提醒用户,如果使用Spring的注解配置,比如@Repository或@Service,通常放在实现类上,这时候使用execution表达式指向实现类的方法会更可靠,尤其是当这些方法没有在接口中声明时。 最后,给出一个示例,说明同情况下的写法,帮助用户更好地理解如何选择接口或实现类作为切点表达式的目标。</think>在Spring AOP中,切点表达式既可以针对接口声明,也可以针对实现类声明,但具体效果取决于**代理机制**和**方法调用方式**。以下是关键点总结: --- ### 1. **两种代理机制的区别** - **JDK动态代理**(基于接口) 代理对象会实现目标接口,仅能拦截接口中声明的方法。 - **CGLIB代理**(基于继承) 代理对象会继承目标类,可拦截所有方法(包括非接口方法)。 --- ### 2. **切点表达式如何选择** #### 情况①:拦截接口中声明的方法 ```java // 匹配接口的所有方法(无论代理机制) @Pointcut("execution(* com.example.UserService.*(..))") public void interfacePointcut() {} ``` - **适用场景** 确保所有实现类统一拦截接口方法(推荐面向接口编程时使用)。 - **注意** JDK代理只能拦截接口方法,CGLIB代理可拦截接口和实现类方法。 #### 情况②:拦截实现类特有的方法 ```java // 匹配实现类的所有方法(需CGLIB代理) @Pointcut("execution(* com.example.UserServiceImpl.*(..))") public void implClassPointcut() {} ``` - **适用场景** 需要拦截实现类新增的方法(未在接口中声明的方法)。 - **注意** 如果使用JDK代理,此类方法无法被拦截。 --- ### 3. **关键匹配规则** - `execution`:基于**方法签名**匹配代码定义位置直接相关。 - `within`:匹配**类或包**的执行范围。 - `@target`/`@within`:基于注解匹配--- ### 4. **最佳实践建议** 1. **优先面向接口** 如果方法在接口中声明,优先使用接口路径定义切点,增强代码可维护性。 2. **明确代理方式** 通过`proxy-target-class=true`强制使用CGLIB代理: ```properties spring.aop.proxy-target-class=true ``` 3. **验证切点有效性** 使用`Arround`建议打印`this.getClass().getName()`,观察代理类型: ```java @Around("interfacePointcut()") public Object log(ProceedingJoinPoint pjp) { System.out.println("Proxy Type: " + pjp.getThis().getClass().getName()); return pjp.proceed(); } ``` --- ### 示例场景 ```java public interface OrderService { void createOrder(); } public class OrderServiceImpl implements OrderService { public void createOrder() { /* ... */ } // 接口方法 public void internalCheck() { /* ... */ } // 实现类特有方法 } ``` - **切点 `execution(* OrderService.*(..))`** 拦截`createOrder()`(无论代理方式)。 - **切点 `execution(* OrderServiceImpl.*(..))`** 需CGLIB代理才能拦截`createOrder()`和`internalCheck()`。 --- 总结:**优先通过接口定义切点**,若需拦截实现类特有方法或使用CGLIB代理,再针对实现类编写表达式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值