Spring AOP 切点详解

本文详细介绍了Spring AOP中的10种切点表达式,包括execution、within、this、target、args等,并提供了示例说明。此外,还讲解了切点的组合使用和公共切点的抽取,帮助读者深入理解Spring AOP的切点概念。
摘要由CSDN通过智能技术生成

本文内容

Spring 10种切点表达式详解
切点的组合使用
公共切点的定义

声明切点@Poincut

@Poincut 的使用格式如下:

@Poincut("PCD") // 切点表达式 表示对哪些方法进行增强
public void pc(){
   } // 切点签名,返回值必须为void

10种切点表达式

AspectJ的切点指示符AspectJ pointcut designators (PCD) ,也就是俗称的切点表达式,Spring中支持10种,如下表:
在这里插入图片描述

简单介绍下AspectJ中常用的3个通配符:

*:匹配任何数量字符
..:匹配任何数量字符的重复,如任何数量子包,任何数量方法参数
+:匹配指定类型及其子类型,仅作为后缀防过载类型模式后面。

execution

用于匹配方法执行,最常用。
格式说明

   execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
                throws-pattern?)
其中带 ?号的 modifiers-pattern?,declaring-type-pattern?,throws-pattern?是可选项
ret-type-pattern,name-pattern, parameters-pattern是必选项
modifier-pattern? 修饰符匹配,如public 表示匹配公有方法,*表示任意修饰符
ret-type-pattern 返回值匹配,* 表示任何返回值,全路径的类名等
declaring-type-pattern? 类路径匹配
name-pattern 方法名匹配,* 代表所有,xx*代表以xx开头的所有方法
(param-pattern) 参数匹配,指定方法参数(声明的类型),(..)代表所有参数,(*,String)代表第一个参数为任何值,第二个为String类型,(..,String)代表最后一个参数是String类型
throws-pattern? 异常类型匹配

举例说明

public class PointcutExecution {
   

    // com.crab.spring.aop.demo02包下任何类的任意方法
    @Pointcut("execution(* com.crab.spring.aop.demo02.*.*(..))")
    public void m1(){
   }

    // com.crab.spring.aop.demo02包及其子包下任何类的任意方法
    @Pointcut("execution(* com.crab.spring.aop.demo02..*.*(..))")
    public void m2(){
   }

    // com.crab.spring.aop包及其子包下IService接口的任意无参方法
    @Pointcut("execution(* com.crab.spring.aop..IService.*(..))")
    public void m3(){
   }

    // com.crab.spring.aop包及其子包下IService接口及其子类型的任意无参方法
    @Pointcut("execution(* com.crab.spring.aop..IService+.*(..))")
    public void m4(){
   }

    // com.crab.spring.aop.demo02.UserService类中有且只有一个String参数的方法
    @Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(String))")
    public void m5(){
   }

    // com.crab.spring.aop.demo02.UserService类中参数个数为2且最后一个参数类型是String的方法
    @Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(*,String))")
    public void m6(){
   }

    // com.crab.spring.aop.demo02.UserService类中最后一个参数类型是String的方法
    @Pointcut("execution(* com.crab.spring.aop.demo02.UserService.*(..,String))")
    public void m7(){
   }
}

within
格式说明

within(类型表达式):目标对象target的类型是否和within中指定的类型匹配

匹配规则: target.getClass().equals(within表达式中指定的类型)

举例说明

public class PointcutWithin {
   
    // 匹配 com.crab.spring.aop.demo02包及其子包下任何类的任何方法
    @Pointcut("within(com.crab.spring.aop.demo02..*)")
    public void m() {
   
    }

    // 匹配m.crab.spring.aop.demo02包及其子包下IService类型及其子类型的任何方法
    @Pointcut("within(com.crab.spring.aop.demo02..IService+)")
    public void m2() {
   
    }

    // 匹配com.crab.spring.aop.demo02.UserService类中所有方法,不含其子类
    @Pointcut("within(com.crab.spring.aop.demo02.UserService)")
    public void m3() {
   
    }
}

this
格式说明

this(类型全限定名):通过aop创建的代理对象的类型是否和this中指定的类型匹配;this中使用的表达式必须是类型全限定名,不支持通配符。

this(x)的匹配规则是:x.getClass.isAssingableFrom(proxy.getClass)

举例说明

package com.crab.spring.aop.demo02.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.ClassUtils;

/**
 * @author zfd
 * @version v1.0
 * @date 2022/2/6 21:41
 * @关于我 请关注公众号 螃蟹的Java笔记 获取更多技术系列
 */
@Aspect
public class PointcutThis {
   
    interface I1{
   
        void m();
    }
    static class C1 implements I1{
   

        @Override
        public void m() {
   
            System.out.println("C1 m()");
        }
    }
	// 匹配 I1类型或是其子类
    @Pointcut("this(com.crab.spring.aop.demo02.aspectj.PointcutThis.I1)")
    public void pc(){
   }

    @Before("pc()")
    public void before(JoinPoint joinPoint) {
   
        System.out.println("before: " + joinPoint);
    }

    public static void main(String[] args) {
   
        C1 target = new C1();
        AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
        proxyFactory.setTarget(target);
        // proxyFactory.setProxyTargetClass(true);
        // 获取C1上所有接口 spring工具类提供的方法
        Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(target);
        // 设置代理接口
        proxyFactory.setInterfaces(allInterfaces);
        // 添加切面
        proxyFactory.addAspect(PointcutThis.class);
        // 获取代理
        I1 proxy = proxyFactory.getProxy();
        // 调用方法
        proxy.m();
        System.out.println("JDK代理? " + AopUtils.isJdkDynamicProxy(proxy));
        System.out.println("CGLIB代理? " + AopUtils.isCglibProxy(proxy));
        //判断代理对象是否是C1类型的
        System.out.println(C1.class.isAssignableFrom(proxy.getClass()));
    }

}

来观察下输出

before: execution(void com.crab.spring.aop.demo02.aspectj.PointcutThis$C1.m())
C1 m()
JDK代理? false
CGLIB代理? true
true

使用JDK动态代理生成的代理对象,其类型是I1类型。

思考下:将切点表达式改成下面的输出结果是?

// 匹配 C1类型或是其子类
@Pointcut("this(com.crab.spring.aop.demo02.aspectj.PointcutThis.C1)")
public void pc(){}

target
格式说明

target(类型全限定名):判断目标对象的类型是否和指定的类型匹配;表达式必须是类型全限定名,不支持通配符。

target(x)匹配规则:x.getClass().isAssignableFrom(target.getClass());

举例说明

@Aspect
public class PointcutTarget {
   
    interface I1{
   
        void m();
    }
    static class C1 implements I1{
   

        @Override
        public void m() {
   
            System.out.println("C1 m()");
        }
    }

    // 匹配目标类型必须是
    @Pointcut("target(com.crab.spring.aop.demo02.aspectj.PointcutTarget.C1)")
    public void pc(){
   }

    @Before("pc()")
    public void before(JoinPoint joinPoint) {
   
        System.out.println("before: " + joinPoint);
    }

    public static void main(String[] args) {
   
        C1 target = new C1();
        AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
        proxyFactory.setTarget
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值