你的位置:首页 > Java教程

[Java教程]Spring AOP 5种通知与java动态代理


1 public interface ArithmeticCalculator {2 3   int add(int i, int j);4   int sub(int i, int j);5   6   int mul(int i, int j);7   int div(int i, int j);8   9 }

接口,要求为每个方法前后添加日志
 1 @Component("arithmeticCalculator") 2 public class ArithmeticCalculatorImpl implements ArithmeticCalculator { 3  4   @Override 5   public int add(int i, int j) { 6     int result = i + j; 7     return result; 8   } 9 10   @Override11   public int sub(int i, int j) {12     int result = i - j;13     return result;14   }15 16   @Override17   public int mul(int i, int j) {18     int result = i * j;19     return result;20   }21 22   @Override23   public int div(int i, int j) {24     int result = i / j;25     return result;26   }27 28 }

接口的实现类
 1 public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator { 2  3    4   @Override 5   public int add(int i, int j) { 6     System.out.println("The method add begins with [" + i + "," + j + "]"); 7     int result = i + j; 8     System.out.println("The method add ends with " + result); 9     return result;10   }11 12   @Override13   public int sub(int i, int j) {14     System.out.println("The method sub begins with [" + i + "," + j + "]");15     int result = i - j;16     System.out.println("The method sub ends with " + result);17     return result;18   }19 20   @Override21   public int mul(int i, int j) {22     System.out.println("The method mul begins with [" + i + "," + j + "]");23     int result = i * j;24     System.out.println("The method mul ends with " + result);25     return result;26   }27 28   @Override29   public int div(int i, int j) {30     System.out.println("The method div begins with [" + i + "," + j + "]");31     int result = i / j;32     System.out.println("The method div ends with " + result);33     return result;34   }35 36 }

方法一:手动实现为方法添加日志
 1 public class ArithmeticCalculatorLoggingProxy { 2    3    4   private ArithmeticCalculator target; 5    6   public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) { 7     super(); 8     this.target = target; 9   }10 11 12   public ArithmeticCalculator getLoggingProxy(){13     ArithmeticCalculator proxy = null;14     15     ClassLoader loader = target.getClass().getClassLoader();16     Class [] interfaces = new Class[]{ArithmeticCalculator.class};17     InvocationHandler h = new InvocationHandler() {18       /*method 方法19        *args 参数 20        * */21       @Override22       public Object invoke(Object proxy, Method method, Object[] args)23           throws Throwable {24         String methodName = method.getName();25         26         //前置通知27         System.out.println("[before] The method " + methodName + " begins with " + Arrays.asList(args));28         29         Object result = null;30         try {31           32           result = method.invoke(target, args);//返回通知33           34         } catch (NullPointerException e) {35           e.printStackTrace();36           //异常通知37         }38         //后置通知39         System.out.println("[after] The method ends with " + result);40         41         return result;42       }43     };44     45     proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);46     47     return proxy;48   }49 }

方法二:利用动态代理模式实现为方法添加日志
 1 /** 2  * AOP  3  * 1. 导入jar包 4  * com.springsource.net.sf.cglib-2.2.0.jar 5  * com.springsource.org.aopalliance-1.0.0.jar 6  * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar 7  * spring-aspects-4.0.0.RELEASE.jar 8  *  9  * 2. 在配置文件中加入AOP的命名空间10  * http://www.springframework.org/schema/aop"11  * 12  * 3. 基于注解的方式13  * <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>14  * <aop:aspectj-autoproxy></aop:aspectj-autoproxy>15  * 16  * 4.把横切关注点的代码抽象到切面的类中17  *  @Aspect18  *   @Component19  *   public class LoggingAspect {}20  *21  * 5.AspectJ支持5种类型的通知注解22  *  @Before()前置通知,在方法开始前执行23  *  @After()后置通知,在方法执行后执行,无论抛异常都会执行;不能访问方法执行的结果24  *  @AfterRunning()返回通知,在方法返回结果后执行(即方法正常结束后才执行);可以得到方法执行的结果25  *  @AfterThrowing()异常通知,在方法抛出异常时执行26  *  @Around()环绕通知,围绕着方法执行27  * 6.AspectJ表达式28  * execution(public int com.aop.beans.ArithmeticCalculator.*(int, int)) 29  * execution(* com.aop.beans.*.*(int, int))30  * 31  * 7.JoinPoint32  * 通过他可以得到方法的信息33 */34 35 //把这个类放入到IOC容器中@Component;再声明为一个切面@Aspect36 @Aspect37 @Component38 public class LoggingAspect {39   //该方法是一个前置通知,即在目标方法开始前执行@Before()40   @Before("execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))")41   public void beforeMethod(JoinPoint joinPoint){42     String methodName = joinPoint.getSignature().getName();//得到方法名43     Object [] args = joinPoint.getArgs();//得到参数44     45     System.out.println("前置通知:The method " + methodName + " begins with " + Arrays.asList(args));46   }47   48   @After("execution(* com.aop.beans.*.*(..))")//位置为这个包下的所有类、所有方法、不论参数是什么类型49   public void afterMethod(JoinPoint joinPoint){50     String methodName = joinPoint.getSignature().getName();51     System.out.println("后置通知:The method " + methodName + " ends");52   }53   54   55   @AfterReturning(value="execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))",56       returning="result")57   public void afterReturning(JoinPoint joinPoint, Object result){58     String methodName = joinPoint.getSignature().getName();59     System.out.println("返回通知:The method " + methodName + " ends with " + result);60   }61   62 63   @AfterThrowing(value="execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))",64       throwing="e")65   public void afterThrowing(JoinPoint joinPoint, Exception e){66     String methodName = joinPoint.getSignature().getName();67     System.out.println("异常通知:The method " + methodName + " occurs excetion:" + e);68   }69   70   /*71    * 环绕通知功能相当于动态代理的全过程,需要有ProceedingJoinPoint 类型的参数;72    * pjd 参数可以决定是否执行目标方法73    * 环绕通知必须有返回值,返回值即为目标方法的返回值74    * 75    * 76   @Around("execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))")77   public Object aroundMethod(ProceedingJoinPoint pjd){78     79     Object result = null;//返回值80     String methodName = pjd.getSignature().getName();//得到方法名81     82     try {83       //前置通知84       System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));85       result = pjd.proceed();//执行方法 //返回通知86       System.out.println("The method " + methodName + " ends with " + result);87     } catch (Throwable e) {88       //异常通知89       System.out.println("The method " + methodName + " occurs exception:" + e);90       throw new RuntimeException(e);91     }92     //后置通知93     System.out.println("The method " + methodName + " ends");94     95     return result;96   }97   */98   99 }

方法三:利用AspectJ实现为方法添加日志
 1 <??> 2 <beans ="http://www.springframework.org/schema/beans" 3   ="http://www.w3.org/2001/  4   ="http://www.springframework.org/schema/aop" 5   ="http://www.springframework.org/schema/context" 6   xsi:schemaLocation="http://www.springframework.org/schema/beans  7     http://www.springframework.org/schema/beans/spring-beans.xsd 8     http://www.springframework.org/schema/aop  9     http://www.springframework.org/schema/aop/spring-aop-4.0.xsd10     http://www.springframework.org/schema/context 11     http://www.springframework.org/schema/context/spring-context-4.0.xsd">12 13   <!-- 自动扫描的包; 扫描@注解,添加到IOC容器中,让Spring管理-->14   <context:component-scan base-package="com.aop.beans"></context:component-scan>15 16   <!-- 使 AspectJ 的注解起作用 ; autoproxy自动代理-->17   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>18 19 </beans>

beans-aop.
 1 public class Main { 2    3   public static void main(String[] args) { 4     /*代理模式实现添加日志功能 5     ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorImpl();     6     arithmeticCalculator = new ArithmeticCalculatorLoggingProxy(arithmeticCalculator).getLoggingProxy();     7     int result = arithmeticCalculator.add(11, 12); 8     System.out.println("result:" + result); 9     result = arithmeticCalculator.div(21, 3);10     System.out.println("result:" + result);11     */12 13     //AOP实现添加日志功能14     ApplicationContext ctx = new ClassPath);15     ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");16     17     System.out.println(arithmeticCalculator.getClass().getName());18     19     int result = arithmeticCalculator.add(11, 12);20     System.out.println("result:" + result);21     result = arithmeticCalculator.div(21, 2);22     System.out.println("result:" + result);23     24   }25   26 }

测试类