自定义Spring AOP切面使用时导致失效踩坑

自定义Spring AOP切面使用时导致失效踩坑

一.背景

我司有一个爬虫的项目需要将爬到的数据回推到公司内部系统,原先是直接通过http请求同步回推数据的,因为爬虫项目是部署在公司外部的,请求公司内部系统的时候没有加任何验证,现在需要加上一个校验,当然只是一个简单的加解密的过程,由于各种客观原因并不会搞得特别复杂,简而言之就是在请求的header中添加一个key-vlue.

二.过程

2.1 如何获取到请求头中的header属性呢?

由于公司内部的接口调用都是基于公司的框架操作的,所有的请求都是被框架包装了一层,但是没有暴露获取header的API,因为有专门的一套检验的过程,但是我们又想自己获取到header的属性,本着解决问题的思路,这个时候其实就需要根据源码去看下框架是如果流转的,既然是自己封装的肯定需要拦截到请求,通过看代码发现,框架自定义了一个servlet继承了httpServlet在自定义的servlet中重写了service方法,然后将拦截住的请求存入一个HttpContext上下文中,然后通过存入ThreadLocal中,因为每个线程的本地内存都是不一样的这样每一个请求都被隔离开来,既然存了当然再请求完成后就需要销毁,就这样找到了怎么获取到请求并获取请求中的header属性.

2.2 自定义注解

/**
 * @Author jmle
 * @Date 2022/6/21 13:37
 * @Version 1.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestAnnotation {
}

2.3 自定义切面

/**
 * @Author jmle
 * @Date 2022/6/21 13:39
 * @Version 1.0
 */
@Aspect
@Component
public class RequestAspect {
    @Pointcut("@annotation(requestAnnotation)")
    public void requestPointCut(RequestAnnotation requestAnnotation){

    }


    @Around(value = "requestPointCut(requestAnnotation)")
    public void around(ProceedingJoinPoint joinPoint,RequestAnnotation requestAnnotation) throws Throwable {
        HttpRequestWrapper request = HttpRequestContext.getInstance().request();
        //验证过程省略
        System.out.println(request.getHeader("token"));
        joinPoint.proceed();
    }
}

2.4 模拟场景

抽象基类代码
public abstract class AbstractBaseRequest<TReqeust, TResponse> {

    public TResponse handle(TReqeust request) {
        return process(request);
    }

    /**
     * 处理方法
     *
     * @param request
     * @return
     */
    protected abstract TResponse process(TReqeust request);
}
子类实现
@Component
public class TestRequestService extends AbstractBaseRequest<TestRequest, TestResponse> {
    @Override
    protected TestResponse process(TestRequest request) {
        //业务逻辑处理
    }
}
2.5 发现问题

从2.4可以看出,项目中定义了一个抽象的基类,然后每个不一样的请求继承这个基类,比如取消订单,查询订单,各自实现基类的process然后按各自的业务逻辑进行处理,这个时候按照正常的逻辑将RequestAnnotation这个注解加入到TestRequestService类的process方法中就可以实现代码的检验逻辑拦截,但是实际上是没有生效的,当时真的是百思不得其解,只能根据’子类继承父类并实现父类方法导致Spring AOP切面失效’关键字去Google,但是查出来的答案却不是想要的.

2.6 猜想

找不到想要的答案就只能根据自己的经验进行猜想了,这个时候需要做的就是验证切面是否生效,此时我将注解加到基类的handle方法中,发现是可以拦截到的,这就间接的证明了AOP是有效的,只是用的地方不对导致AOP失效了,这个时候换了一个思路查询谷歌,那就用’导致Spring AOP失效的几种原因’从搜索到答案中,找到了一条this关键字调用内部方法导致Spring AOP失效感觉有点像.

2.7 验证猜想

既然找到了this关键字调用内部方法导致Spring AOP失效的这条答案那就要结合所学知识进行佐证,从代码结构中可以看出,子类继承父类并实现了父类的方法,并且在父类中调用子类的方法满足this调用,因为子类也拥有父类的handle方法,所以是满足this调用的这种场景的。

2.8 this关键字为什么会导致AOP失效呢?

this代表的是当前对象,使用当前对象调用内部方法是不会走代理的,因为AOP拦截的方法是被代理的对象所调用,其实导致AOP失效的场景有很多种,之前记得背面试题的时候背过,但当真正的遇到的时候可能一时不知道怎么分析.

2.9 解决方案

其实网上解决的方案比较多,第一种就是将本类的对象注入本类中,然后通过Srping的对象调用process方法就能绕开this调用,第二种就从ApplicationContext.getBean()获取到子类对象,然后再进行调用,其实原因都一样,都是获取到代理对象然后绕开this调用,当然还有第三种方案,网上有很多答案,我最终这三种都没有用,因为不符合实际情况,最终采用的是将注解加在最顶层的入口,这样就完美避开了this调用了.

三.总结

很多时候真的经验很重要,单纯的背过知识点,却没有遇到真实的场景感受是不一样的,当你真的遇到场景并理解为什么会这样,可能对你的帮助会更大,脚踏实地,一步一步走才是当下最应该做的事。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP 失效的原因可能有很多,以下是一些可能的原因: 1. 未配置正确的切面表达式:切面表达式定义了应该在哪些方法上应用切面。如果切面表达式不正确,就无法正确地匹配到目标方法,并且切面将无法生效。 2. 目标方法没有被代理:Spring AOP 使用动态代理来实现切面,在运行生成代理对象,并将切面应用于代理对象上的目标方法。如果目标方法没有被代理,切面将无法生效。 3. 目标方法被直接调用而不是通过代理调用:如果目标对象的方法被其他部分直接调用,而不是通过生成的代理对象调用,那么切面将无法生效。 4. 切面的顺序问题:在一个应用中可能存在多个切面,每个切面都可以定义相同或不同的切面表达式。如果切面的顺序不正确,可能会导致切面失效,例如一个切面将目标方法拦截之后,另一个切面再次拦截该方法。 5. 使用错误的切面类型:Spring AOP 支持多种类型的切面,如前置通知、后置通知、异常通知等。如果使用了错误的切面类型,或者切面类型不匹配目标方法,切面将无法生效。 6. 目标方法没有被正确地扫描到:Spring AOP 使用自动扫描来发现目标方法,并将切面应用于这些方法上。如果目标方法没有被正确地扫描到,切面将无法生效。 总结来说,Spring AOP 失效的原因可能是由于切面表达式的问题、代理问题、调用方式问题、切面顺序问题、切面类型问题、以及扫描问题。为了确保切面生效,我们需要仔细检查配置,并理解Spring AOP的工作原理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值