3. Spring Aop 标签详解

Spring Aop 标签详解

<aop:config>
    <aop:aspect id="beforeAdviceBindingTests" ref="testAspect">
        <aop:before method="oneIntArg" 
                    pointcut="execution(* setAge(int)) and args(age)"/>
        <aop:before method="oneObjectArg" 
                    pointcut="execution(* getAge()) and this(bean)"/>
        <aop:before method="oneIntAndOneObject"
                    pointcut="execution(* setAge(..)) and args(age) and target(bean)" 
                    arg-names="age,bean"/>
        <aop:before method="needsJoinPoint" pointcut="execution(* getAge())"/>
        <aop:before method="needsJoinPointStaticPart" pointcut="execution(* getAge())"/>
    aop:aspect>

    
    <aop:aspect ref="authenticationLogger">
        <aop:pointcut id="authenticationMethodWithString"
                      expression="execution(boolean *..SecurityManager.authenticate(..))
                                  and args(username,java.lang.String)"/>
        <aop:before pointcut-ref="authenticationMethodWithString"
                    method="logAuthenticationAttempt(java.lang.String)"/>
    aop:aspect>
aop:config>

是配置aop的切入点

是切面信息,id 是切面标识,ref 是切面的定义类

是切点信息,id 是切点标识,expression 切点表达式,常见的切点表达式:

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

    args是和execution用在一起,用来过滤要被代理的方法的

    • 独立使用:args(param1, param2, ..) 表示目标方法只需匹配前面param1和param2的类型即可
    • arg-names一起使用:arg-names(param1, param2, ..) 表示参数1和参数2的类型由arg-names所代表方法的参数确定

    举例说明:

    /**
     * 切面定义
     */
    @Aspect
    public class AccessArgAdviceTest {
           
        @AfterReturning(
                pointcut="execution(* com.abc.service.*.access*(..)) && args(time, name)",
                returning="returnValue")
        public void access(Date time, Object returnValue, String name) {
           
            System.out.println("目标方法中的参数String = " + name);
            System.out.println("目标方法中的参数Date = " + time);
            System.out.println("目标方法的返回结果returnValue = " + returnValue);
        }
    }
    

    表达式中增加了args(time, name)部分,意味着可以在增强处理方法(access方法)中定义time和name两个属性——这两个形参的类型可以随意指定,但一旦指定了这两个参数的类型,则这两个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二个参数类型为name的方法(方法参数个数和类型若有不同均不匹配)。

    注意,在定义returning的时候,这个值(即上面的returning="returnValue"中的returnValue)作为增强处理方法的形参时,位置可以随意。

    //将被AccessArgAdviceTest的access方法匹配
    public String accessAdvice(Date d, String n) {
           
        System.out.println("方法:accessAdvice");
        return "aa";
    }
    
  • @args():用于匹配当前执行的方法传入的 参数 持有 指定注解 的执行方法

  • execution():用于匹配 方法 执行的连接点

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

    modifiers-pattern 方法修饰符:如public,可以不需要,?代表可以缺失

    ret-type-pattern 方法返回值类型,不可缺失

    declaring-type-pattern 类限定名匹配,可以缺失

    name-pattern 方法名,不能缺失

    param-pattern 方法参数,不能缺失

    throws-pattern 异常类型,可以缺失

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

    <aop:aspect ref="thisAsInterfaceAndTargetAsClassCounter">
        <aop:before method="increment"
                    pointcut="this(org.springframework.aop.aspectj.TestInterface)" />
    aop:aspect>
    

    表示当前AOP对象实现了 TestInterface接口的任何方法

  • target():用于匹配当前目标对象类型的执行方法,注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配

    <aop:aspect ref="thisAsInterfaceAndTargetAsClassCounter">
        <aop:before method="increment"
                    pointcut="this(org.springframework.aop.aspectj.TestInterface)
                              and target(org.springframework.aop.aspectj.TestImpl)" />
    aop:aspect>
    

    表示当前AOP对象实现了 TestInterface接口的任何方法 并且 当前目标对象(非AOP对象)实现了 TestImpl 类的任何方法

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

    <aop:config >
        <aop:advisor id="logUserAdvisor" 
                     pointcut="@within(org.springframework.scripting.groovy.Log)"
                     advice-ref="logUserAdvice"/>
    aop:config>
    

    表示任何目标对象持有Log注解的类方法,必须是在目标对象上声明这个注解,在接口上声明的对它不起作用

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

    <aop:config>
        <aop:pointcut id="getNameCalls"
                      expression="execution(* getName(..)) and within(*..ITestBean+)"/>
        <aop:advisor id="getAgeAdvisor"
                     pointcut="execution(* *..ITestBean.getAge(..))"
                     advice-ref="getAgeCounter"/>
        <aop:advisor id="getNameAdvisor" 
                     pointcut-ref="getNameCalls" advice-ref="getNameCounter"/>
    aop:config>
    

    表示所有包下ITestBean类型及子类型的任何方法

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

    <aop:config >
        <aop:advisor id="logUserAdvisor" 
                     pointcut="@within(org.springframework.scripting.groovy.Log)"
                     advice-ref="logUserAdvice"/>
    aop:config>
    

    表示任何目标对象对应的类型持有Log注解的类方法,必须是在目标对象上声明这个注解,在接口上声明的对它不起作用。

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

    @within@target针对类的注解,@annotation是针对方法的注解

在方法调用之前调用通知

<aop:config>
    <aop:aspect id="countAgeCalls" ref="countingAdvice">
        <aop:pointcut id="pc" expression="execution(* getAge())"/>
        <aop:before pointcut-ref="pc" method="myBeforeAdvice" />
        <aop:after pointcut-ref="pc" method="myAfterAdvice" />
        <aop:after-returning pointcut-ref="pc" 
                             method="myAfterReturningAdvice" returning="age"/>
        <aop:after-throwing pointcut-ref="pc" 
                            method="myAfterThrowingAdvice" throwing="ex"/>
        <aop:around pointcut-ref="pc" method="myAroundAdvice"/>
    aop:aspect>
aop:config>

在方法完成之后调用通知,无论方法执行成功与否

在方法执行成功之后调用通知

在方法抛出异常后进行通知

通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

定义通知器(通知器跟切面一样,也包括通知和切点)

<aop:config >
    <aop:advisor id="logUserAdvisor" 
                 pointcut="@within(org.springframework.scripting.groovy.Log)" 
                 advice-ref="logUserAdvice"/>
aop:config>

<bean id="logUserAdvice" class="org.springframework.scripting.groovy.LogUserAdvice" />

引入和织入的概念区别:

  • 引入概念:允许我们向现有的类中添加方法或属性

  • 织入概念:将切面应用到目标对象来创建的代理对象过程

    切面在指定的连接点被织入到目标对象中,在目标对象的生命周期中有多个点可以织入

    • 编译期——切面在目标类编译时期被织入,这种方式需要特殊编译器。AspectJ的织入编译器就是以这种方式织入切面。
    • 类加载期——切面在类加载到
    • JVM ,这种方式需要特殊的类加载器,他可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5 的 LTW 就支持这种织入方式
    • 运行期——切面在应用运行期间的某个时刻被织入。一般情况下,在织入切面时候,AOP 容器会为目标对象动态的创建代理对象。Spring AOP 就是以这种方式织入切面。

你可能感兴趣的:(Spring,专题,spring)