Spring中的AOP(六)——定义切入点和切入点指示符

定义切入点java

    在前文(点击查看)中使用到的AdviceTest类中同一个切点(即* com.abc.service.*.advice*(..)匹配的链接点)却重复定义了屡次,这显然不符合软件设计的原则,为了解决这个问题,AspectJ和Spring都提供了切入点的定义。所谓定义切入点,其实质就是为一个切入点表达式起一个名称,从而容许在多个加强处理中重用该名称。
编程

    Spring AOP只支持以Spring Bean的方法执行组做为链接点,因此能够把切入点看做全部能和切入表达式匹配的Bean方法。切入点定义包含两个部分:
框架

  • 一个切入点表达式:用于指定切入点和哪些方法进行匹配this

  • 一个包含名字和任意参数的方法签名:将做为切入点的名称spa

    在@AspectJ风格的AOP中,切入点签名采用一个普通的方法定义(方法体一般为空)来提供(方法名即为切点名),且该方法的返回值必须为void,切入点表达式需使用@Pointcut注解来标注。下面的代码片断定义了一个切入点,这个切入点将匹配任何名为transfer的方法的执行:.net

//使用@Pointcut注解时指定切入点表达式
@Pointcut("execution(* transfer(..))")
//使用一个返回值为void,方法体为空的方法来命名切入点,方法名即为切点名
private void myPointcut(){}

    切入点表达式,也就是组成@Pointcut注解的值,是规范的AspectJ 5切入点表达式。若是想要了解更多的关于AspectJ切入点语言,请参见AspectJ编程指南。
设计

    一旦采用上面的代码片断定义了名为myPointcut的切入点以后,程序就能够屡次重复使用该切点了,甚至能够在其余切面类、其余包的切面类里使用该切点,至因而否能够在其余切面类、其余包下使用这个切点,那就要看该方法前的访问控制修饰符了——本例中myPointcut使用private修饰,则意味着仅能在当前切面类中使用这个切点。
代理

    若是须要使用本切面类中的切点,则可在使用@Pointcut注解时,指定value属性值为已有的切入点,以下:
code

@AfterReturning(pointcut="myPointcut()", returning="returnValue")
public void log(String message, Object returnValue) {
    //do something...
}

    从指定pointcut来看,其语法很是相似于Java中调用方法——只是该方法表明一个切点,其实质是为该加强处理方法定义一个切入点表达式。若是须要使用其余类中定义的切点,则定义这些切点的方法的修饰符不能为private。如今假设在另外一个类PointcutDefinition中定义了一个名为myPointcutTest的切点:对象

public class PointcutDefinition {
    @Pointcut("execution(* something(..))")
    //访问控制符为public,这个切点能够在其余任何地方引用
    public void myPointcutTest(){}
}

    则在引用的时候须要带上类名,例如:

@AfterReturning(
    pointcut="PointcutDefinition.myPointcutTest() && args(message)", 
    returning="returnValue")
public void log(String message, Object returnValue) {
    //do something...
}


切入点指示符

    前面定义切点表达式时使用了大量的execution表达式,其中execution就是一个切入点指示符。Spring AOP仅支持部分AspectJ的切入点指示符,但Spring AOP还额外支持一个bean切入点指示符。不只如此,由于Spring AOP只支持使用方法调用做为链接点,因此Spring AOP的切入点指示符仅匹配方法执行的链接点。

    完整的AspectJ切入点语言支持大量切入点指示符,可是Spring并不支持它们。它们是:call,get,preinitialization,staticinitialization,initialization,handler,adviceexecution,withincode,cflow,cflowbelow,if,@this和@withincode。一旦在Spring AOP中使用这些切点指示符,就会抛出IllegalArgumentException。

    Spring AOP支持的切入点指示符有以下几个:

  • execution:用于匹配执行方法的链接点,这是Spring AOP中国最主要的切入点指示符。该切入点的用法也相对复杂,execution表达式的格式以下:

    execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

    上面的格式中,execution是不变的,用于做为execution表达式的开头,整个表达式中几个参数的详细解释以下:

    • modifier-pattern:指定方法的修饰符,支持通配符,该部分能够省略

    • ret-type-pattern:指定返回值类型,支持通配符,可使用“*”来通配全部的返回值类型

    • declaring-type-pattern:指定方法所属的类,支持通配符,该部分能够省略

    • name-pattern:指定匹配的方法名,支持通配符,可使用“*”来通配全部的方法名

    • param-pattern:指定方法的形参列表,支持两个通配符,“*”和“..”,其中“*”表明一个任意类型的参数,而“..”表明0个或多个任意类型的参数。

    • throw-pattern:指定方法声明抛出的异常,支持通配符,该部分能够省略

    以下是几个execution表达式:

    execution(public * * (..))//匹配全部public方法

    execution(* set*(..))//匹配以set开始的方法

    execution(* com.abc.service.AdviceManager.* (..))//匹配AdviceManager中任意方法

    execution(* com.abc.service.*.* (..))//匹配com.abc.servcie包中任意类的任意方法

  • within:限定匹配特定类型的链接点,当使用Spring AOP的时候,只能匹配方法执行的链接点。下面是几个例子:

  • within(com.abc.service.*)//匹配com.abc.service包中的任意链接点

    within(com.abc.service..*)//匹配com.abc.service包或子包中任意的链接点

  • this:用于指定AOP代理必须是指定类型的实例,用于匹配该对象的全部链接点。当使用Spring AOP的时候,只能匹配方法执行的链接点。下面是个例子:

        this(com.abc.service.AdviceManager)//匹配实现了AdviceManager接口的代理对象的全部链接点,在Spring中只是方法执行的链接点

  • target:用于限定目标对象必须是指定类型的实例,用于匹配该对象的全部链接点。当使用Spring AOP的时候,只能匹配方法执行的链接点。下面是个例子:

        target(com.abc.servcie.AdviceManager)//匹配实现了AdviceManager接口的目标对象的全部链接点,在Spring中只是方法执行的链接点

  • args:用于对链接点的参数类型进行限制,要求参数的类型时指定类型的实例。一样,当使用Spring AOP的时候,只能匹配方法执行的链接点。下面是个例子:

  • args(java.io.Serializable)//匹配只接受一个参数,且参数类型是Serializable的全部链接点,在Spring中只是方法执行的链接点

    注意,这个例子与使用execution(* *(java.io.Serializable))定义的切点不一样,args版本只匹配运行时动态传入参数值是Serializable类型的情形,而execution版本则匹配方法签名只包含一个Serializable类型的形参的方法。


    另外,Spring AOP还提供了一个名为bean的切入点提示符,它是Spring AOP额外支持的,并非AspectJ所支持的切入点指示符。这个指示符对Spring框架来讲很是有用:它将指定为Spring中的哪一个Bean织入加强处理。固然,Spring AOP中只能使用方法执行做为链接点。

  • bean:用于指定只匹配该Bean实例内的链接点,实际上只能使用方法执行做为链接点。定义bean表达式时须要传入Bean的id或name,支持使用"*"通配符。下面是几个例子:

        bean(adviceManager)//匹配adviceManager实例内方法执行的链接点

        bean(*Manager)//匹配以Manager结尾的实例内方法执行的链接点


使用组合切点表达式

    Spring支持使用以下三个逻辑运算符来组合切入点表达式:

  • &&:要求链接点同时匹配两个切点表达式

  • ||:要求链接点匹配至少一个切入点表达式

  • !:要求链接点不匹配指定的切入点表达式

    其实在以前介绍args的时候,已经用到了“&&”运算符:

pointcut("execution(* com.abc.service.*.*(..) && args(name))")

    上面的pointcut由两个表达式组成,并且使用&&来组合这两个表达式,所以链接点须要同时知足这两个表达式才能被织入加强处理。

相关文章
相关标签/搜索