Spring的AOP编程

Spring 中的AOP编程是与JAVA中OOP同等的,在OOP中模块的基本单位是类,而在AOP中模块的基本单位是切面,其实AOP的底层还是通过代理来实现的。
一、基本术语
1、Aspect
将横切多个业务对象的程序独立出来模块化,该模块可以无侵入式地集成到业务对象中。
如,事务、日志、权限
2、Advice
是指切面的具体实现,如记录日志、验证权限
通知有各种类型,其中包括”before”、”around”、”throw”等通知。
3、Joinpoint
通知执行的时机,如方法调用时或抛出异常时
4、Pointcut
切入点是感兴趣的连接点(即并不是每个方法调用时都会反执行)。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(如执行某个特定名称的方法时)
切入点表达式如何和连接点匹配是AOP的核心
5、Target
被一个或者多个切面所通知的对象
是一个被代理对象
6、AOP Proxy
AOP框架创建的对象,用来实现切面的功能
在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理
7、Weaving
把切面连接到其它 的应用程序类型或者对象上,并创建一个被通知对象,是在运行时完成织入。
二 、声明一个Pointcut
Pointcut声明中可以用的标识符有execution、within、this、target、args、@target、@args、@within、@annotation。
下面是一个简单的Pointcut声明

@Pointcut("execution(* transfer(..))")// the pointcut 表达式
private void anyOldTransfer() {}// the pointcut 方法签名

要注意的是方法签名只能是返回空值。
该Pointcut匹配的是方法名为transfer,返回值和参数个数任意的方法执行。

其中Pointcut表达式遵从如下模式:

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

modifiers-pattern:代表匹配的方法的访问控制权限(public 、protected、private可选项)
ret-type-pattern:代表匹配方法的返回值类型(必选项)
declaring-type-pattern:声明类型(可选项),如果指定了,就应该包括一个.接尾,把它添加到相关的组件中。
name-pattern:匹配的方法名。
param-pattern:匹配的参数,如果是..则表示有0或多个参数,如果没有则表示无参数。
下面是常见的Pointcut表达式的例子:
1、匹配任意公有方法的执行
execution(public * *(..))
2、任意以set开头的方法的执行
execution(* set*(..))
3、AccountService接口中方法的执行
execution(* com.xyz.service.AccountService.*(..))
4、service包下方法的执行
execution(* com.xyz.service.*.*(..))
5、service包及子包中方法的执行
execution(* com.xyz.service..*.*(..))
6、任何位于service包下的连接点
within(com.xyz.service.*)
7、任何位于service包及其子包下的连接点
within(com.xyz.service..*)
注:Pointcut表达式中也可以有&&,| |,!这些逻辑表达式,如:

@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.someapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}

上例中名为tradingOperation的连接点引用了名字为anyPublicOperationinTrading的连接点,当上面两个条件同时满足时才会匹配tradingOperation连接点
三、 声明一个advice
1、Before advice
该通知可用@Before注解

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}

这个表示dataAccessOperation方法调用之前doAccessCheck方法会被调用

2、After returning advice
该通知在方法正常返回时被调用

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
    @AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
    public void doAccessCheck() {
    // ...
    }
}

当然如果你想接收相关的返回值还可以这样配置

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
    @AfterReturning(
    pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
    returning="retVal")
    public void doAccessCheck(Object retVal) {
        // ...
    }
}

注:returning="retVal"中的retVal值必须和doAccessCheck方法参数名一致,当dataAccessOperation()返回时,它的返回值会被retVal接收从而传给doAccessCheck()函数,这里引用的dataAccessOperation()是一个接入点
2、After throwing advice
这个通知是在方法产生异常时执行

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
    @AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
    public void doRecoveryActions() {
    // ...
    }
}

和获取返回值一样,在doRecoveryActions方法中我们也可以通过一个参数接收一个异常

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
    @AfterThrowing(
    pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
    throwing="ex")
    public void doRecoveryActions(DataAccessException ex) {
        // ...
    }
}

4、After (finally) advice
这个通知是在方法无论以怎样的方式退出时,都会执行。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
    @After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
    public void doReleaseLock() {
    // ...
    }
}

5、Around advice
该通知可运行在方法执行之前和之后,也就是同时具有BeforeAfter的功能,不过BeforeAfter能完成的需求,就不要用Around advice了。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
    @Around("com.xyz.myapp.SystemArchitecture.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }
}

该通知方法中还要接收一个ProceedingJoinPoint的参数,这样执行目标方法,目标方法是通过pjp.proceed();完成调用的

猜你喜欢

转载自blog.csdn.net/yangkaige111/article/details/80207417
今日推荐