博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring AOP
阅读量:5017 次
发布时间:2019-06-12

本文共 6272 字,大约阅读时间需要 20 分钟。

AOP简介

  AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统OOP的补充
  AOP的主要编程对象时切面(aspect),而切面模块化横切关注点
  在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的对象(切面)里。
  AOP的好处
    每个事务逻辑位于一个位置,代码不分散,便于维护和升级
    业务模块更简洁,只包含核心业务代码
AOP术语
  切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
  通知(Advice):切面必须要完成的工作
  目标(Target):被通知的对象
  代理(Proxy):向目标对象应用通知之后创建的对象
  连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点有两个信息确定:方法表示的程序执行点,相对点表示的方位。例如ArithmeticCalculator#add()方法执行前的连接点,执行点为ArithmeticCalculator#add();方位为该方法执行前的位置。
  切点(pointcut):每个类都拥有多个连接点。例如ArithmeticCalculator的所有方法其实都是连接点,即连接点是程序类中客观存在的事务。AOP通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面实现一个简单的计算器来解释AOP的产生背景。

接口:ArithmeticCalculator.java,定义加减乘除方法

1 package com.yl.spring.aop.helloworld; 2  3 public interface ArithmeticCalculator { 4      5     int add(int i, int j); 6     int sub(int i, int j); 7      8     int mul(int i, int j); 9     int div(int i, int j);10 }

实现类:ArithmeticCalculatorImpl.java 实现基本的加减乘除

1 package com.yl.spring.aop.helloworld; 2  3 public class ArithmeticCalculatorImpl implements ArithmeticCalculator { 4  5     @Override 6     public int add(int i, int j) { 7         int result = i + j; 8         return result; 9         10     }11 12     @Override13     public int sub(int i, int j) {14         int result = i - j;15         return result;16     }17 18     @Override19     public int mul(int i, int j) {20         int result = i * j;21         return result;22     }23 24     @Override25     public int div(int i, int j) {26         int result = i / j;27         return result;28     }29 30 }

至此,上面两段代码实现了基本的计算器。新的需求时在计算前后增加日志。

最简单的实现就是在每个方法的计算语句前后增加日志代码,即输出语句。具体实现如下:

ArithmeticCalculatorLoggingImpl.java

1 package com.yl.spring.aop.helloworld; 2  3 public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator { 4  5     @Override 6     public int add(int i, int j) { 7         System.out.println("the method add begin with[" + i + ", " + j + "]"); 8         int result = i + j; 9         System.out.println("the method add end with " +result);10         return result;11         12     }13 14     @Override15     public int sub(int i, int j) {16         System.out.println("the method sub begin with[" + i + ", " + j + "]");17         int result = i - j;18         System.out.println("the method sub end with " +result);19         return result;20     }21 22     @Override23     public int mul(int i, int j) {24         System.out.println("the method mul begin with[" + i + ", " + j + "]");25         int result = i * j;26         System.out.println("the method mul end with " +result);27         return result;28     }29 30     @Override31     public int div(int i, int j) {32         System.out.println("the method div begin with[" + i + ", " + j + "]");33         int result = i / j;34         System.out.println("the method div end with " +result);35         return result;36     }37 38 }

 但是上述的实现方法增加了业务模块的复杂度,而且修改日志代码时也不方便。

下面在介绍一个新的方法,即动态代理。具体实现如下:

ArithmeticCalculatorLoggingProxy.java

1 package com.yl.spring.aop.helloworld; 2  3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 import java.util.Arrays; 7  8 import org.springframework.beans.propertyeditors.ClassArrayEditor; 9 10 public class ArithmeticCalculatorLoggingProxy {11     //要代理的对象12     private ArithmeticCalculator target;13     14     public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {15         this.target = target;16     }17     18     public ArithmeticCalculator getLoggingProxy() {19         ArithmeticCalculator proxy = null;20         21         //代理对象由哪一个类加载器负责加载22         ClassLoader loader = target.getClass().getClassLoader();23         //代理对象的类型,即其中有哪些方法24         Class [] interfaces = new Class[]{ArithmeticCalculator.class};25         //当调用代理对象其中的方法时,该执行的代码26         InvocationHandler h =  new InvocationHandler() {27             /**28              * proxy:正在返回的那个代理对象,一般情况下,在invoke方法中都不使用该对象29              * method:正在调用的方法30              * args:调用方法时,传入的参数31              */32             @Override33             public Object invoke(Object proxy, Method method, Object[] args)34                     throws Throwable {35                 //此句话或造成循环调用,最终内存溢出36                 //System.out.println(proxy.toString());37                 38                 39                 String methodName = method.getName();40                 //日志41                 System.out.println("the method " + methodName + " begin with " + Arrays.asList(args));42                 //执行该方法43                 Object result = method.invoke(target, args);44                 //日志45                 System.out.println("the method " + methodName + " end with " + result);46                 return result;47             }48         };49         50         proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);51         52         return proxy;53     }54 55 }

至此,动态代理的实现完毕。

测试类:

1 package com.yl.spring.aop.helloworld; 2  3 public class Main { 4     public static void main(String[] args) { 5          6         /*//测试日志 7         ArithmeticCalculator arithmeticCalculator = null; 8         arithmeticCalculator = new ArithmeticCalculatorLoggingImpl(); 9         10         int result = arithmeticCalculator.add(1, 2);11         System.out.println("-->" + result);12         13         result = arithmeticCalculator.div(4, 2);14         System.out.println("-->" + result);*/15         16         //动态代理测试17         ArithmeticCalculator target = new ArithmeticCalculatorImpl();18         ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy();19         20         System.out.println(proxy.getClass().getName());21         22         int result = proxy.add(1, 2);23         System.out.println("-->" + result);24         25         result = proxy.div(4, 2);26         System.out.println("-->" + result);27     }28 }

AOP的具体用法还请参考本系列的后续文章......

 

转载于:https://www.cnblogs.com/dreamfree/p/4093768.html

你可能感兴趣的文章
SQLServer 基本语法
查看>>
Python入门基础知识(1) :locals() 和globals()
查看>>
python模块之multiprocessing模块, threading模块, concurrent.futures模块
查看>>
css-文字和图片在容器内垂直居中的简单方法
查看>>
杭电3784(继续xxx定律)
查看>>
PHP 的 HMAC_SHA1算法 实现
查看>>
深入理解javascript原型和闭包_____全部
查看>>
2016年中国的SaaS服务商企业研究
查看>>
HTML5:离线存储(缓存机制)-IndexDB
查看>>
9-5
查看>>
Laxcus大数据管理系统2.0(5)- 第二章 数据组织
查看>>
kafka入门样例 for java
查看>>
Redis存储AccessToken
查看>>
Use commons-email-1.1.jar+activation.jar+mail.jar to send Email
查看>>
hdu 2160 Sequence one(DFS)
查看>>
ATM实验感受
查看>>
csharp基础
查看>>
hdu4497 正整数唯一分解定理应用
查看>>
html5 拖曳功能的实现[转]
查看>>
[BZOJ 2049] [Sdoi2008] Cave 洞穴勘测 【LCT】
查看>>