• Spring AOP 5种通知与java动态代理


    接口,要求为每个方法前后添加日志 
     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     @Override
    11     public int sub(int i, int j) {
    12         int result = i - j;
    13         return result;
    14     }
    15 
    16     @Override
    17     public int mul(int i, int j) {
    18         int result = i * j;
    19         return result;
    20     }
    21 
    22     @Override
    23     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     @Override
    13     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     @Override
    21     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     @Override
    29     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             @Override
    22             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  * xmlns:aop="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  *   @Aspect
    18  *     @Component
    19  *     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.JoinPoint
    32  * 通过他可以得到方法的信息
    33  */
    34 
    35 //把这个类放入到IOC容器中@Component;再声明为一个切面@Aspect
    36 @Aspect
    37 @Component
    38 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 }
    方法三:利用Spring AOP AspectJ实现为方法添加日志
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     4     xmlns:aop="http://www.springframework.org/schema/aop"
     5     xmlns:context="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.xsd
    10         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.xml
     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 ClassPathXmlApplicationContext("com/aop/beans/beans-aop.xml");
    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 }
    测试类
  • 相关阅读:
    POJ2983Is the Information Reliable
    POJ2706Connect
    POJ1716Integer Intervals
    js Number 转为 百分比
    c# Unicode编码
    json datatable
    分割js 数组
    IQueryable定义一个扩展方法。分页
    sql 计算岁数
    sql 获取一个周的周一和周日
  • 原文地址:https://www.cnblogs.com/wwzyy/p/5151471.html
Copyright © 2020-2023  润新知