Spring AspectJ注解

3 篇文章 0 订阅
一、知识点     

       要在Spring中注册AspectJ aspect, 只需要将它们声明为IoC容器中的Bean实例就行了。在Spring IoC容器中启用AspectJ,容器将自动为匹配AspectJ aspect的Bean创建代理。

       用AspectJ注解编写的aspect只是一个带有@Aspect注解的Java类。通知(Advice)是带有—个通知注解的简单Java方法。AspectJ支持5种通知注解:@Before、@After、@AfterRetuming、@AfterThrowing 和@Around。

二、代码示例

     (1)前置通知

       为了创建在程序特定执行点之前处理横切关注点的前置通知(Before Advice),你可以使用@Before注解,并将切入点表达式作为注解值。

/*  
  * Copyright 2013-2015  
  */

package com.codeproject.jackie.springrecipesnote.springaop;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * Title: CaculatorLoggingAspect.java
 * 
 * @author jackie
 * @since May 3, 2013 9:11:49 PM
 * @version V1.0
 */
@Aspect
public class CaculatorLoggingAspect {
    private Log log = LogFactory.getLog(this.getClass());
    
    @Before("execution(* ArithmeticCalculator.add( . . ))")
    public void logBefore() {
        log.info("The method add() begins"); 
    }
}

切入点表达式匹配ArithmeticCalculator接口的add()方法的执行。表达式前导的星号匹配任何修饰符(public、protected和private)和任何返回类型。参数列表中的两个点匹配任何数量的参数。

       为了注册这个aspect,只需要在IoC容器中声明它的一个Bean实例。如果其他Bean不引用,这个aspect Bean可以是匿名的。  

<bean class="com.codeproject.jackie.springrecipesnote.springaop.CaculatorLoggingAspect" />
  测试类如下:

package com.codeproject.jackie.springrecipesnote.springaop;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Unit test for Aop Advice.
 */
public class AdviceTest {
    
    private ApplicationContext applicationContext;

    @Test
    public void testBeforeAdvice() {
        applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator)applicationContext.getBean("arithmeticCalculator");
        arithmeticCalculator.add(1, 2);
        arithmeticCalculator.sub(1, 2);
        arithmeticCalculator.mul(1, 2);
        arithmeticCalculator.div(1, 2);
        
        UnitCalculator unitCalculator = (UnitCalculator) applicationContext.getBean("unitCalculator");
        unitCalculator.kilogramToPound(100);
        unitCalculator.kilometerToMile(100);    
    }
}
          切入点匹配的执行点称作连接点(Join Point)。在这个术语中,切入点是匹配一组连接点的表达式,而通知是在特定连接点上采取的行动。为了使通知访问当前连接点的细节,可以在通知方法中声明一个JoinPoint 类型的参数。然后,可以访问连接点的细节,如方法名称和参数值。现在,可以将类名和方法名改为通配符,扩展切入点以匹配所有方法。

    @Before("execution(* *.*( . . ))")
    public void logBefore(JoinPoint joinPoint) {
        log.info("The method " +  joinPoint.getSignature().getName() + "() begins with " + Arrays.toString(joinPoint.getArgs())) ; 
    }
      (2)最终通知

       最终通知(After Advice)在连接点结束之后执行,不管返回结果还是抛出异常。下面的最终通知记录计算器方法的结束。一个aspect可以包含一个或者多个通知。

@After("execution(* *.*( . . ))")
    public void logAfter(JoinPoint joinPoint) {
        log.info("The method " +  joinPoint.getSignature().getName() + "() ends") ; 
    }
      (3)后置通知   

       最终通知(After Advice)不管连接点正常返冋还是抛出异常都执行。如果你希望仅当连接点返回时记录,应该用后置通知(after returning advice)替换最终通知。

    @AfterReturning("execution(* *.*( . . ))")
    public void logAfterReturning(JoinPoint joinPoint) {
        log.info("The method " +  joinPoint.getSignature().getName() + "() ends") ; 
    }
       在后置通知中,可以在注解中添加一个returning属性,访问连接点的返回值。这个属性的值应该是通知方法的参数名称,用于传入返回值。然后,必须用这个名称向通知方法的签名中添加一个参数。在运行时,Spring AOP通过这个参数传入返回值。 还要注意,原来的切入点表达式必须改在pointcut属性中表现。

    @AfterReturning(pointcut="execution(* *.*( . . ))", returning="result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        log.info("The method " +  joinPoint.getSignature().getName() + "() ends with " + result) ; 
    }
(4)异常通知

       异常通知(after throwing advice)仅当连接点抛出异常时执行

    @AfterThrowing("execution(* *.*( . . ))")
    public void logAfterThrowing(JoinPoint joinPoint) {
        log.info("The method " +  joinPoint.getSignature().getName() + "()") ; 
    }
类似地,连接点抛出的异常也可以通过为@AfterThrowing注解添加一个throwing属性来访问。Throwable类型是Java 语言中所有错误和异常的超类。所以,下面的通知将捕捉连接点抛出的任何错误和异常:   

    @AfterThrowing(pointcut = "execution(* *.*( . . ))", throwing="e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        log.info("An exception  " + e + " has been thrown in " + joinPoint.getSignature().getName() + "()") ; 
    }
     (5)环绕通知

       环绕通知(around advice)是所有通知类型中最强大的。它获得连接点的完全控制,这样你可以在一个通知中组合前述通知的所有行动。你甚至可以控制何时以及是否继续原来的连接点的执行。 

       下面的环绕通知组合了前面创建的前置、后置和异常抛出通知。注意,对于环绕通知,连接点的参数类型必须是ProceedingJoinPoint。它是JoinPoint的一个子接口,允许你控制何时继续原始的连接点。

@Around("execution(* *.*( . . ))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("The method " +  joinPoint.getSignature().getName() + "() begins with " + Arrays.toString(joinPoint.getArgs())) ; 
        
        try {
            Object result = joinPoint.proceed();
            log.info("The method " +  joinPoint.getSignature().getName() + "() ends with " + result) ; 
            return result;   
        } catch (IllegalArgumentException e) {
            log.info("An exception  " + e + " has been thrown in " + joinPoint.getSignature().getName() + "()") ; 
            throw e;
        }
    }

环绕通知类型非常强大和灵活,你甚至可以修改原始参数值并且修改最后返回值。必须非常小心地使用这类通知,因为很容易忘记继续原始的连接点的调用。

       提示:选择通知类型的通用原则是使用满足你的要求的最弱小的类型。



转自:

Spring攻略学习笔记(3.02)------用AspectJ注解声明Aspects

Spring3.0中的AOP配置方法

基于Annotation的Spring AOP: @AfterThrowing


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值