Spring框架学习笔记(8)——AspectJ实现AOP

使用代理对象实现AOP虽然可以满足需求,但是较为复杂,而Spring提供一种简单的实现AOP的方法AspectJ

同样的计算器的DEMO

首先配置applicationContext.xml

<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>
    
<!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

 

在计算器实现类ArithmeticCalculatorImpl上加注解@Component("arithmeticCalculator")

创建类LoggingAspect作为计算器的一个切面,添加注解@Aspect和@Component

LoggingAspect里添加一个方法beforeMethod即前置通知

/**
 * 在 com.atguigu.spring.aop.ArithmeticCalculator 接口的每一个实现类的每一个方法开始之前执行一段代码
 */
@Before("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); }

切入点表达式

execution(public <返回类型>int <接口方法,*为通配符(..)为参数,代表这个接口的每个实现类的每个方法>com.atguigu.spring.aop.ArithmeticCalculator.*(..))
这里也可以指定某一个方法,比如add(..)
切入点表达式还可以使用|| && !这些连接符
execution(public * *.add(..))||execution(public * *.div(..))


连接点参数类型

JoinPoint可以访问更多细节比如方法名和参数
对于环绕通知来说, 连接点的参数类型必须是 ProceedingJoinPoint . 它是 JoinPoint 的子接口, 允许控制何时执行, 是否执行连接点.


完成这些就可以运行main方法

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
    
    System.out.println(arithmeticCalculator.getClass().getName());
    
    int result = arithmeticCalculator.add(1, 2);
    System.out.println("result:" + result);
    
    result = arithmeticCalculator.div(1000, 10);
    System.out.println("result:" + result);

类似的可以添加其他通知

AspectJ 支持 5 种类型的通知注解:

@Before: 前置通知, 在方法执行之前执行

@After: 后置通知, 在方法执行之后执行

@AfterRunning: 返回通知, 在方法返回结果之后执行

@AfterThrowing: 异常通知, 在方法抛出异常之后

@Around: 环绕通知, 围绕着方法执行

日志切面详细代码

/**
 * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高
 */
@Order(2)
@Aspect
@Component
public class LoggingAspect {
    
    /**
     * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. 
     * 使用 @Pointcut 来声明切入点表达式. 
     * 后面的其他通知直接使用方法名来引用当前的切入点表达式. 
     */
    @Pointcut("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
    public void declareJointPointExpression(){}
    
    /**
     * 在 com.atguigu.spring.aop.ArithmeticCalculator 接口的每一个实现类的每一个方法开始之前执行一段代码
     */
    @Before("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        Object [] args = joinPoint.getArgs();
        
        System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
    }
    
    /**
     * 在方法执行之后执行的代码. 无论该方法是否出现异常
     */
    @After("declareJointPointExpression()")
    public void afterMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends");
    }
    
    /**
     * 在方法法正常结束受执行的代码
     * 返回通知是可以访问到方法的返回值的!
     */
    @AfterReturning(value="declareJointPointExpression()",
            returning="result")
    public void afterReturning(JoinPoint joinPoint, Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " ends with " + result);
    }
    
    /**
     * 在目标方法出现异常时会执行的代码.
     * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码
     */
    @AfterThrowing(value="declareJointPointExpression()",
            throwing="e")
    public void afterThrowing(JoinPoint joinPoint, Exception e){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " occurs excetion:" + e);
    }
}

环绕通知示例代码

Spring4.0支持@order注解当有多个切面的时候可以使用@order来为切面的执行顺序进行排序

比如添加一个验证切面添加注解@Order(1),日志切面添加注解@Order(2)

 
 
原文地址:https://www.cnblogs.com/huangjian2/p/6274110.html