@Pointcut这个注解是我们使用spring的AOP功能时用到的。其他的先不说,今天来讲讲切点的使用。
注意使用的是AspectJ

概括

我们在使用spring aop的过程中会遇到几个点,Join Point和Pointcut,也就是连接点和切点。

  • Join Point
    连接点是一个程序执行的步骤,例如一个方法的执行和异常的处理,简而言之连接点就表示方法的执行
  • Pointcut
    切点是用于匹配和描述连接点的,具体就是Spring AOP通过切点来定位/匹配到哪些连接点(方法),而后进行前后功能处理
  • 切点表达式
    切点用来定义连接点的语法,如下:
    @Pointcut("execution(public int cn.shafish.aop.BusinessClass.calculate(int,int))")
    public void pointCut(){}

    这时切点表达式作为@Pointcut的参数,代码的意思是pointCut方法被定义为切点签名方法,作用就是使得通知的注解可以通过这个切点签名方法连接到切点。具体例子查看spring aop的章节例子。还没写完

切点表达式出现的场景

我们上面提到过@Pointcut,其参数用到的是切点表达式。这里是使用注解的方式,除此外我们还可以用xml文件的<aop:pointcut>标签来配置表达式定位连接点。

<aop:config>
    <aop:pointcut id="anyDaoMethod"
      expression="@target(org.springframework.stereotype.Repository)"/>
</aop:config>

切点指示符

切点指示符是切点定义的关键字,比如上面提到的execution,开发人员可以通过切点指示符来匹配连接点。
一共有九种切点指示符:execution、within、this、target、args、@target、@args、@within、@annotation
未完待续,聊天聊过头了,明天继续

execution

使用频率比较高,用来匹配方法,使用的时候需要指定方法的完整路径,比如访问修饰符、返回类型、包名、类名、方法名、参数
例子;

@Pointcut("execution(public String cn.shafish.service.DoThing.doSomething(int,String))")

上面的切点表达式精确地匹配了DoThing类中地doSomething方法,如果需要匹配该类的所有方法,则用*代替,比如:

@Pointcut("execution(public String cn.shafish.service.DoThing.*(..))")

除了方法名使用*代替外,参数使用..指代匹配任意个参数,包括零个。

within

使用within指示符也可以达到execution的效果,within用来限定连接点属于某个确定类型的类。

@Pointcut("within(org.baeldung.dao.FooDao)")
@Pointcut("within(org.baeldung..*)")

this

匹配连接点所属的对象引用是某个特定类型实例

target

匹配的连接点所属目标对象必须是指定类型的实例

这里说说AspectJ在实现代理时有两种方式:
1、如果当前对象引用的类型没有实现自接口时,spring aop使用生成一个基于CGLIB的代理类实现切面编程
2、如果当前对象引用实现了某个接口时,Spring aop使用JDK的动态代理机制来实现切面编程

所以上面那两个的区别 :this指示符就是用来匹配基于CGLIB的代理类,通俗的来讲就是,如果当前要代理的类对象没有实现某个接口的话,则使用this;target指示符用于基于JDK动态代理的代理类,通俗的来讲就是如果当前要代理的目标对象有实现了某个接口的话,则使用target

args

用来匹配方法参数

@Pointcut("execution(* *..find*(Long))")

例子匹配所有以find开头的方法并且只有一个long类型的参数。

@target

匹配指定连接点,这个连接点所属的目标对象的类有一个指定的注解

@Pointcut("@target(org.springframework.stereotype.Repository)")

@args

匹配连接点的参数的,@args指出连接点在运行时传过来的参数的类必须要有指定的注解,假设我们希望切入所有在运行时接受实@Entity注解的bean对象的方法

@Pointcut("@args(org.baeldung.aop.annotations.Entity)")
public void methodsAcceptingEntities() {}

为了在切面里接收并使用这个被@Entity的对象,我们需要提供一个参数给切面通知:JointPoint:

@Before("methodsAcceptingEntities()")
public void logMethodAcceptionEntityAnnotatedBean(JoinPoint jp) {
    logger.info("Accepting beans with @Entity annotation: " + jp.getArgs()[0]);
}

@within

匹配必须包括某个注解的的类里的所有连接点

@Pointcut("@within(org.springframework.stereotype.Repository)")
//上面的切点跟以下这个切点是等效的:
@Pointcut("within(@org.springframework.stereotype.Repository *)")

@annotation

匹配那些有指定注解的连接点

@Pointcut("@annotation(org.baeldung.aop.annotations.Loggable)")
public void loggableMethods() {}

切点表达式组合

可以使用&&、||、!、三种运算符来组合切点表达式,表示与或非的关系。

@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods() {}
@Pointcut("execution(* *..create*(Long,..))")
public void firstLongParamMethods() {}
@Pointcut("repositoryMethods() && firstLongParamMethods()")
public void entityCreationMethods() {}

参考:
http://www.baeldung.com/spring-aop-pointcut-tutorial
https://github.com/eugenp/tutorials/tree/master/spring-mvc-java