AOP 基础知识

        AOP(Aspect Oriented Programming)是为了解决某些场景下代码重复问题的一种编程技术,允许程序模块化横向切割关注点或横向切割典型的责任划分。其能够封装多个类中不同单元的相同功能,把应用业务逻辑和系统服务分开,经常用在日志和事务管理上。

        利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
        AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。

基本概念:

Aspect

• 方面:Aspect,横切多个类的某个功能描述。比如,一个日志模块可以被称作日志的 AOP 切面。 切面类一般加@Aspect@Compent注解

JointPoint

• 连接点:JointPoint,程序执行过程中的某个函数调用。其代表一个应用程序的某个位置,在这个位置我们可以插入一个 AOP 切面,它实际上是一个应用程序执行Spring AOP 的位置。

Advice

• 通知:Advice,是一个在方法执行前或执行后要做的动作,实际上是程序执行时要通过 Spring AOP 框架触发的代码段。Spring 切面可以应用以下 5 种类型的通知。

before:前置通知,在一个方法执行前被调用。

after:在方法执行之后调用的通知,无论方法执行是否成功。

after-returning:仅当方法成功完成后执行的通知。

after-throwing:在方法抛出异常退出时执行的通知。

around:在方法执行之前和之后调用的通知。

PointCut

• 切入点:PointCut,是映射到一个或一组连接点的指示符,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。Spring AOP 支持的 AspectJ 切入点指示符如下。

execution

execution:用于匹配方法执行的连接点。一般用于指定方法的执行,用的最多
匹配所有方法 execution(* *(..))
匹配所有公共方法 execution(public * *(..))
匹配所有add()方法 execution(* add())
匹配所有抛出Exception的方法 execution(* *(..) throws Exception)
匹配类或者接口中的方法 execution(* com.web.ServiceImpl.*(..))
匹配指定包(不包含子包)下所有类中的所有方法 execution(* com.web.*.*(..))
匹配指定包及其子包下的所有类中以add开头的所有public方法 execution(public * com.web..*.add*(..))

within

• within:用于匹配指定类型内的方法执行。

匹配service包(不包含子包)中任意类的方法 within(com.web.service.*)
匹配service包及子包中任意类的方法 within(com.web.service..*)

this

• this:用于匹配当前 AOP 代理对象类型的执行方法。注意是 AOP 代理对象的类型匹配,这样就可能包括引入接口的类型匹配。

匹配生成的代理对象是IOrgService类型的所有方法的外部调用 this(com.web.OrgService)

target

• target:用于匹配当前目标对象类型的执行方法。注意是目标对象的类型匹配,这样就不包括引入接口的类型匹配。
匹配被代理的目标对象能够转换为OrgService类型的所有方法的外部调用target(com.web.spring.aop.service.OrgService)


this 和 target 的不同点:
-- this作用于代理对象,target作用于目标对象
-- this表示目标对象被代理之后生成的代理对象和指定的类型匹配会被拦截,匹配的是代理对象
-- target表示目标对象和指定的类型匹配会被拦截,匹配的是目标对象

args

• args:用于匹配当前执行的方法传入的参数为指定类型的执行方法。

匹配任何不带参数的方法 args()
匹配任何只带一个String类型参数的方法 args(java.lang.String)
匹配带任意参数的方法 args(..)
匹配带任意个参数,但是第一个参数的类型是String的方法 args(java.lang.String,..)
匹配带任意个参数,但是最后一个参数的类型是String的方法 args(..,java.lang.String)

@within

• @within:用于匹配所有持有指定注解类型内的方法。

匹配被调用的方法声明的类上拥有RestController注解 @within(com.web.aop.annotation.RestController)

@target

• @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解。

匹配方法参数类型上拥有WebHookCallBack注解的方法调用。如我们有一个方法add(WebHookDTO param)接收一个WebHookDTO类型的参数,而WebHookDTO这个类是拥有注解WebHookCallBack @args(com.web.webHook.annotation.WebHookCallBack)

@args

• @args:用于匹配当前执行的方法传入的参数持有指定注解的执行方法。

annotation

• @annotation:用于匹配当前执行方法持有指定注解的方法。

匹配所有拥有WebHookCallBack注解的方法 @annotation(com.web.webHook.annotation.WebHookCallBack)

bean

• bean:Spring AOP 扩展的,AspectJ 没有此指示符,用于匹配特定名称的 Bean 对

象的执行方法。

bean(abc)    匹配Spring Bean容器中id或name为abc的bean的方法调用
bean(org*)   匹配所有id或name为以org开头的bean的方法调用

reference pointcut

• reference pointcut:表示引用其他命名切入点,只有 @ApectJ 风格支持,Schema风格不支持。

其中类型匹配的语法如下。

•  *:匹配任何数量字符。

•  ..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包,而在方法参数模式中匹配任何数量参数。

•  +:匹配指定类型的子类型,仅能作为后缀放在类型模式后边。

匹配类型表达式:注解? 类的全限定名字;匹配方法执行表达式:注解?修饰符?返回值类型 类型声明?方法名(参数列表)异常列表?

此外,多个切入点表达式是可以组合的,AspectJ 使用且(&&)、或(||)、非(!)来组合切入点表达式,为了方便 XML 配置,Spring AOP 提供了 and、or、not 来代替 &&、||、!。

bean(orgService) && args()  匹配id或name为orgService的bean的所有无参方法。
bean(orgService) || @annotation(WebHookCallBack)  匹配id或name为orgService的bean的方法调用,或者是方法上使用了WebHookCallBack注解的方法调用。
bean(orgService) && !args()  匹配id或name为orgService的bean的所有有参方法调用。

Aspect  常见例子

@Aspect
@Component
public class WebHookCallBackAspect {
    protected final Logger log = LoggerFactory.getLogger(getClass());

     
    @Pointcut("@annotation(com.web.webHook.annotation.WebHookCallBack)")
    public void callBackPointCut() {
    }

    @Around("callBackPointCut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("===========进入around环绕方法!=========== \n");
        // 调用目标方法之前执行的动作
        System.out.println(" 调用方法之前 : 执行! \n");
        // 调用方法的参数
        Object[] args = pjp.getArgs();  
        // 调用的方法名
        String method = pjp.getSignature().getName();  
        // 获取目标对象
        Object target = pjp.getTarget();
        // 执行完方法的返回值:调用 proceed() 方法,就会触发切入点方法执行
        Object result = pjp.proceed();
        System.out.println(" 输出:" + args[0] + ";" + method + ";" + target + ";" + result + "\n");
        System.out.println(" 调用方法结束:之后执行! \n");
        return result;
    }

    // result是结果值
    @AfterReturning(value = "callBackPointCut()", returning = "result")
    protected Object callBackExcute(JoinPoint joinPoint, Object result) {
        log.debug("-----do AfterReturning-----");
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        WebHookCallBack annotation = method.getAnnotation(WebHookCallBack.class);
        log.debug("WebHookCallBack: {}", JSON.toJSONString(annotation));
        
        return null;
    }
}

总结:

        自定义注解会很好用,可以统一处理一些内容。比如:统一处理返回值(@Around),统一处理方法执行后回调处理(@AfterReturning)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天狼1222

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值