AspectJ使用实例

来源:互联网 发布:c语言表白源代码 编辑:程序博客网 时间:2024/05/29 17:13

一、在 Spring 中启用 AspectJ 注解支持

  • 1要在 Spring 应用中使用 AspectJ 注解, 必须在 classpath 下包含 AspectJ 类库: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
    maven 引入

    <dependency><groupId>org.springframework</groupId>  <artifactId>spring-aop</artifactId>  <version>4.1.9.RELEASE</version>  </dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>4.1.9.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId>  <artifactId>aspectjrt</artifactId>  <version>1.6.8</version>  </dependency>  <dependency>  <groupId>org.aspectj</groupId>  <artifactId>aspectjweaver</artifactId>  <version>1.6.8</version>  <scope>runtime</scope>  </dependency>    
  • 2将 aop Schema 添加到 根元素中.
  • 3要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素

    <!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>  
  • 4当 Spring IOC 容器侦测到 Bean 配置文件中的 元素时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理.

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

  • @Before: 前置通知, 在方法执行之前执行
  • @After: 后置通知, 在方法执行之后执行
  • @AfterRunning: 返回通知, 在方法返回结果之后执行
  • @AfterThrowing: 异常通知, 在方法抛出异常之后
  • @Around: 环绕通知, 围绕着方法执行

2.1、使用之前的 计算器接口和实现类 ArithmeticCalculator.java , ArithmeticCalculatorImpl.java

@Component("arithmeticCalculator")public class ArithmeticCalculatorImpl implements ArithmeticCalculator{}  

2.2、在xml中增加扫描注解和aspectj的支持

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">            <!-- 配置自动扫描的包 -->    <context:component-scan base-package="com.hp.spring.aop.annotation"></context:component-scan>        <!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 -->    <aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>  

2.3、编写切面类,定义各种通知

@Aspect //注解定义切面@Componentpublic class LoggingAspect {    //前置通知    @Before("execution(public int com.hp.spring.aop.annatation.ArithmeticCalculator.*(int, int))")    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("execution(* com.hp.spring.aop.annatation.*.*(..))")    public void afterMethod(JoinPoint joinPoint){        String methodName = joinPoint.getSignature().getName();        System.out.println("The method " + methodName + " ends");    }    }  

由于@before 和@after的表达式都一样,所以spring支持对表达式进行抽取成一个方法,抽取后的代码如下:

package com.hp.spring.aop.annotation;import java.util.Arrays;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;/** * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高 */@Order(2) @Aspect@Componentpublic class LoggingAspect {        /**     * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码.      * 使用 @Pointcut 来声明切入点表达式.      * 后面的其他通知直接使用方法名来引用当前的切入点表达式.      */    @Pointcut("execution(public int com.hp.spring.aop.annotation.ArithmeticCalculator.*(..))")    public void declareJointPointExpression(){}        /**     * 在 com.hp.spring.aop.annotation.ArithmeticCalculator 接口的每一个实现类的每一个方法开始之前执行一段代码     */    @Before("declareJointPointExpression()")    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);    }        /**     * 环绕通知需要携带 ProceedingJoinPoint 类型的参数.      * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.     * 且环绕通知必须有返回值, 返回值即为目标方法的返回值     */    /*    @Around("execution(public int com.hp.spring.aop.annotation.ArithmeticCalculator.*(..))")    public Object aroundMethod(ProceedingJoinPoint pjd){                Object result = null;        String methodName = pjd.getSignature().getName();                try {            //前置通知            System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));            //执行目标方法            result = pjd.proceed();            //返回通知            System.out.println("The method " + methodName + " ends with " + result);        } catch (Throwable e) {            //异常通知            System.out.println("The method " + methodName + " occurs exception:" + e);            throw new RuntimeException(e);        }        //后置通知        System.out.println("The method " + methodName + " ends");                return result;    }    */}
  • 切面二
package com.hp.spring.aop.annotation;import java.util.Arrays;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;@Order(1)@Aspect@Componentpublic class VlidationAspect {    @Before("com.hp.spring.aop.annotation.LoggingAspect.declareJointPointExpression()")    public void validateArgs(JoinPoint joinPoint){        System.out.println("-->validate:" + Arrays.asList(joinPoint.getArgs()));    }    }
  • 测试类
package com.hp.spring.aop.annotation;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {        public static void main(String[] args) {                ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-aspectj.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);    }    }

打印出:
com.sun.proxy.$Proxy12
-->validate:[1, 2]
The method add begins with [1, 2]
The method add ends
The method add ends with 3
result:3
-->validate:[1000, 10]
The method div begins with [1000, 10]
The method div ends
The method div ends with 100
result:100

打印的日志中,可以看出,跟动态代理一样,可以定义各类通知。

原创粉丝点击