基于注解的Spring AOP

基于注解的Spring AOP

[1] 导入jar包

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar hamcrest-core-1.3.jar junit-4.12.jar
spring-aop-4.0.0.RELEASE.jar spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar spring-expression-4.0.0.RELEASE.jar

[2]创建被代理类(目标类)
由于我们加入了cglib的支持,所以允许被代理类不实现任何接口。但是这个类必须加入IOC容器,否则Spring没法控制和操作。

@Component
public class Calculator {
    public void add(int a, int b) {
        System.out.println("(a+b) = " + (a+b));
    }
​
    public void sub(int a, int b) {
        System.out.println("(a-b) = " + (a-b));
    }
​
    public void mul(int a, int b) {
        System.out.println("(a×b) = " + (a*b));
    }
​
    public void div(int a, int b) {
        System.out.println("(a÷b) = " + (a/b));
    }
}

[3]创建切面类

@Aspect
@Component
public class LogAspect {
​
    @Before(value="execution(* com.atguigu.spring.aop.target.Calculator.*(..))")
    public void doBeforeLog() {
        System.out.println("[aop log]method begin");
    }
​
    @AfterReturning(value="execution(* com.atguigu.spring.aop.target.Calculator.*(..))")
    public void doSuccessLog() {
        System.out.println("[aop log]method successfully end");
    }
​
    @AfterThrowing(value="execution(* com.atguigu.spring.aop.target.Calculator.*(..))")
    public void doExceptionLog() {
        System.out.println("[aop log]method ended with exception");
    }
​
    @After(value="execution(* com.atguigu.spring.aop.target.Calculator.*(..))")
    public void doAfterLog() {
        System.out.println("[aop log]method finally end");
    }
​
}

[4]环绕通知
环绕通知对应整个try…catch…finally结构,包括前面四种通知的所有功能。

@Aspect
@Component
public class MessageAspect {
​
    @Around(value = "com.atguigu.spring.aop.aspect.LogAspect.declarPointCut()")
    // 环绕通知的通知方法一定要设定有返回值,通常是需要将目标方法执行后的返回值在这里返回
    public Object roundAdvice(ProceedingJoinPoint joinPoint) {
​
        // 获取目标方法名
        String methodName = joinPoint.getSignature().getName();
​
        // 声明一个变量,用来接收目标方法的返回值
        Object targetMethodReturnValue = null;
​
        // 获取外界调用目标方法时传入的实参
        Object[] args = joinPoint.getArgs();
​
        try {
​
            // 调用目标方法之前的位置相当于前置通知
            System.out.println("[环绕] message before target method " + methodName);
​
            // 调用ProceedingJoinPoint对象的proceed(Object[] var1)调用目标方法
            // 将目标方法的返回值赋值给targetMethodReturnValue变量
            targetMethodReturnValue = joinPoint.proceed(args);
​
            // 调用目标方法成功返回之后的位置相当于返回通知
            System.out.println("[环绕]message after target method " + methodName + " success,return value="+targetMethodReturnValue);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
​
            // 调用目标方法抛出异常之后的位置相当于异常通知
            System.out.println("[环绕]message after target method " + methodName + " failed " + throwable.getClass().getName());
        } finally {
            // 调用目标方法最终结束之后的位置相当于后置通知
            System.out.println("[环绕]message after target method " + methodName + " finally end");
        }
​
        return targetMethodReturnValue;
    }
​
}

[5]配置Spring配置文件

<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.atguigu.spring.aop"/>
​
<!-- 启用AspectJ注解 -->
<aop:aspectj-autoproxy/>

[6]junit测试

@Test
public void testAOP() {
    Calculator calculator = iocContainer.getBean(Calculator.class);
    calculator.div(5, 0);
​
    System.out.println("calculator.getClass().getName() = " + calculator.getClass().getName());
}

各个通知获取目标类细节信息

[1]通过JoinPoint接口获取目标方法的方法名、参数

// 使用@Before注解将当前方法定义为前置通知
// value属性:指定切入点表达式,将前置通知“套”在add()方法上
@Before(value = "execution(public void com.atguigu.spring.aop.target.Calculator.div(int,int))")
public void printLogBeforeCoreOperation(JoinPoint joinPoint) {
​
    // 获取方法签名(方法所在类的全类名、方法名等信息)
    Signature signature = joinPoint.getSignature();
​
    // 通过方法签名获取方法名
    String methodName = signature.getName();
​
    // 外界调用目标方法时传入的参数
    Object[] args = joinPoint.getArgs();
​
    System.out.println("[前置]"+ methodName + " method begin" + Arrays.asList(args));
}

[2]方法返回值
在返回通知中,通过@AfterReturning注解的returning属性获取目标方法的返回值

// 使用@AfterReturning注解将当前方法定义为返回通知
@AfterReturning(
        pointcut = "execution(public int com.atguigu.spring.aop.target.Calculator.div(int,int))",
​
        // 使用returning属性指定一个名称,Spring会自动将目标方法的返回值传入到同名的参数位置
        // 注意:目标方法必须确定有返回值,如果目标方法返回值是void,那么Spring给参数位置传入null
        returning = "targetMethodReturnValue"
)
public void printLogAfterCoreOperationSuccess(Object targetMethodReturnValue){
    System.out.println("[返回]method success,return value=" + targetMethodReturnValue);
}

[3]目标方法抛出的异常
在异常通知中,通过@AfterThrowing注解的throwing属性获取目标方法抛出的异常对象

// 使用@AfterThrowing注解将当前方法定义为异常通知
@AfterThrowing(
        value = "execution(public int com.atguigu.spring.aop.target.Calculator.div(int,int))",
    throwing = "exception"
)
public void printLogAfterCoreOperationFailed(Throwable exception) {
    System.out.println("[异常]method failed,exception name=" + exception.getClass().getName());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值