Spring篇 AOP介绍

AOP是什么

        AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面,将某些公共模块抽取出来放到一个可重用模块里,减少系统的重复代码,降低系统的耦合度,增强代码的可操作性和可维护下


使用场景

        一般场景下,AOP被广泛应用在权限认证、日志、事务处理、增强处理、安全监控等等。


AOP的特性

Advice-通知:AOP中的增强处理,通知描述切面何时执行以及如何执行增强处理

Join Point - 连接点:连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法调用、异常抛出。不过在Spring AOP中,Join point是方法调用的连接点

PointCut - 切点:可以插入增强处理的连接点

Aspect - 切面:切面是通知和切点的结合

Introduction - 引入:允许我们向现有的类添加新的方法或者属性

Weaving - 织入:将增强处理添加到目标对象中,并创建一个被增强的代理对象


切点指示器

Aspect 指示器描述
arg()限制连接点匹配参数为指定类型的执行方法
@arg()限制连接点匹配参数由指定注解标注的执行方法
execution匹配连接点的执行方法
this()限制连接点匹配AOP代理的bean引用为指定类型的类
target()限制连接点匹配目标对象为指定类型的类
@target()限制连接点匹配特定的执行对象,这些对象对应类要具备指定类型的注解
within()限制连接点匹配指定的类型
@within()限制连接点匹配指定注解所标注的类型
@annotation限制匹配带有指定注解的连接点

通知注解描述

通知描述
@Before在调用前执行
@After目标方法返回或异常后调用
@AfterReturning方法返回后调用
@AfterThrowing抛出异常后调用
@Around环绕调用

代码实现

@Aspect
@Component
public class TestAop {
    @Pointcut("execution(* cloud2.aop.Filter.after(..))")
    public void point() {
    }

    @Before("point()")
    public void before() {
        System.out.println("before ...");
    }

    @After("point()")
    public void after() {
        System.out.println("After ...");
    }

    @AfterReturning("point()")
    public void afterReturning() {
        System.out.println("AfterReturning ...");
    }

    @Around("point()")
    public void around(ProceedingJoinPoint pj) {
        try {
            System.out.println("Around aaa ...");
            pj.proceed();
            System.out.println("Around bbb ...");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

实现一个USER_ID限流

   

@Slf4j
@Order(-1)
@Aspect
@Component
public class ApiFilterAop implements InitializingBean, DisposableBean, ApplicationContextAware
{
    @Around("@within(org.springframework.web.bind.annotation.RestController)")
    public Object doFilter(ProceedingJoinPoint joinPoint) throws Throwable
    {
        Object[] args = joinPoint.getArgs();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        Object target = joinPoint.getTarget();

        Object[] finalArgs = args;

        for(Object arg : args) {

         // 定义一个父类,参数属于AppRequest 才会进入
         if(arg instanceof AppRequest)
         {
             isAppApi = true;
             AppRequest request = (AppRequest) arg;

             //初始化上下文 - 可扩展request

             //before正序执行
             for(int i = 0; i < filters.size(); i++)
             {
                // Filter filter 为自定义的一个类
                 Filter filter = filters.get(i);
                 finalArgs = filter.before(target, method, args);
              }

              break;
            }
        }
    }
}

 利用redis实现

@Component
public class SentinelFilter implements Filter {
    @Override
    public Object[] before(Object target, Method method, Object... args) throws Exception {
        for (Object arg : args) {
            if (arg instanceof AppRequest) {

                AppRequest request = (AppRequest) arg;
                // 自定义的注解,需要的话联系我
                ApiFilter apiFilter = method.getAnnotation(ApiFilter.class);

                if (apiFilter != null) {

                    long intervalLimit = apiFilter.intervalLimit();
                    String type = apiFilter.type();
                    if (intervalLimit > 0) {
                        String methodName = method.getName();
                        switch (type) {
                            case "IP":
                                // TODO 可扩展IP限流
                                break;
                            case "USERID":
                                //可扩展USERID限流
                                String phone = request.getUserId();

                                //过滤请求
                                String key =             CommonKey.phoneRequestSentinel(phone,methodName);
                                String value = JodisUtils.getInstance().get(key);
                                // 这里写一个断言,存在时则返回

                                JodisUtils.getInstance().setStringEx(key, intervalLimit, "true");
                                break;
                            case "USER_TOKEN":
                                // TODO 可扩展USER_TOKEN限流
                                break;
                            case "DEVICE_NO":
                                // TODO 可扩展DEVICE_NO限流
                                break;
                            default:
                                break;
                        }

                    }
                }
                break;
            }
        }

        return args;
    }
}

AOP执行流程

  1. 首先ApplicationContext会调用AdvisedSupport
  2. AdvisedSupport 主要是为了完成配置文件的解析以及去构建切面、以及区完成切面与切点之间的关系,可以理解为工具类
  3. 解析完成后,调用AopConfig类保存AOP的配置信息
  4. 保存完成通过调用Advice类,发送通知,完成切面的回调。
  5. 最后通过JDKDynamicAopProxy类或者CglibAopProxy生成代理类。

实现原理

        Spring AOP的底层实现原理其实就是动态代理,目前Spring中有两种动态代理方式,一种是JDK反射,一种是cglib方式。

        当目标类是接口类时,就会直接使用jdk的动态代理方式,其余的都是使用cglib动态代理。所以aop的实现有两个关键步骤,一个是要得到代理对象,一个是要利用递归责任链执行前后置通知目标方法。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值