Spring AOP基础
来源:互联网 发布:阿里国际站数据分析 编辑:程序博客网 时间:2024/06/04 01:04
【一】为什么需要 AOP?
<<interface>> Calculator· add(in a:double,in b:double):double· sub(in a:double,in b:double):double· mul(in a:double,in b:double):double· div(in a:double,in b:double):double CalculatorImpl· add(in a:double,in b:double):double· sub(in a:double,in b:double):double· mul(in a:double,in b:double):double· div(in a:double,in b:double):double
需求1-日志:在程序执行期间追踪正在发生的活动
需求2-验证:希望计算器只能处理正数的预算
代码:
public interface Calculator { double add(double a,double b); double sub(double a,double b); double mul(double a,double b); double div(double a,double b);}public class CalculatorLoggingImpl implements Calculator { @Override public double add(double a, double b) { System.out.println("The Method add begins with[" + a + "," + b + "]"); double result = a + b; System.out.println("The Method add End with " + result); return result; } @Override public double sub(double a, double b) { System.out.println("The Method sub begins with[" + a + "," + b + "]"); double result = a - b; System.out.println("The Method sub End with " + result); return result; } @Override public double mul(double a, double b) { System.out.println("The Method mul begins with[" + a + "," + b + "]"); double result = a * b; System.out.println("The Method mul End with " + result); return result; } @Override public double div(double a, double b) { System.out.println("The Method div begins with[" + a + "," + b + "]"); double result = a / b; System.out.println("The Method div End with " + result); return result; }}public class Main { public static void main(String[] args) { Calculator calculator = new CalculatorImpl(); calculator.add(2, 2); calculator.div(2, 2); calculator.mul(2, 2); calculator.sub(2, 2); }}
结果:
The Method add begins with[2.0,2.0]The Method add End with 4.0The Method div begins with[2.0,2.0]The Method div End with 1.0The Method mul begins with[2.0,2.0]The Method mul End with 4.0The Method sub begins with[2.0,2.0]The Method sub End with 0.0
可见,普通方法实现有大量冗余代码,代码分散,不利于维护,且巨麻烦。
改变思路,通过动态代理解决以上问题。
原理:使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上.
代码:
public interface Calculator { double add(double a,double b); double sub(double a,double b); double mul(double a,double b); double div(double a,double b);}public class CalculatorImpl implements Calculator { @Override public double add(double a, double b) { double result = a + b; return result; } @Override public double sub(double a, double b) { double result = a - b; return result; } @Override public double mul(double a, double b) { double result = a * b; return result; } @Override public double div(double a, double b) { double result = a / b; return result; }}public class CalculatorLoggingProxy { //被代理对象 private Calculator target; public CalculatorLoggingProxy(Calculator calculator) { this.target = calculator; } //返回日志代理 public Calculator getLoggingProxy() { Calculator proxy = null; //代理对象由哪一个类加载器负责加载 ClassLoader loader = target.getClass().getClassLoader(); //代理对象的类型, 即其中有哪些方法 Class[] interfaces = new Class[]{Calculator.class}; //当调用代理对象其中的方法时, 该执行的代码 InvocationHandler h = new InvocationHandler() { /** * proxy: 正在返回的代理对象. 一般情况下, 在 invoke 方法中不使用该对象. * method: 正在被调用的方法. * args: 调用方法时, 传入的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { String methodName = method.getName(); //日志 System.out.println("--> spring The Method " + methodName + " begins with" + Arrays.asList(args)); //执行方法 Object result = method.invoke(target, args); System.out.println("--> spring The Method " + methodName + "end with " + result); return result; } }; proxy = (Calculator) Proxy.newProxyInstance(loader, interfaces, h); return proxy; }} public static void main(String[] args) { /*Calculator calculator = new CalculatorLoggingImpl();*/ Calculator target = new CalculatorImpl(); Calculator proxy = new CalculatorLoggingProxy(target).getLoggingProxy(); double add = proxy.add(2, 2); System.out.println("--> " + add); double div = proxy.div(2, 2); System.out.println("--> " + div); double mul = proxy.mul(2, 2); System.out.println("--> " + mul); double sub = proxy.sub(2, 2); System.out.println("--> " + sub); }}
测试结果:
--> spring The Method add begins with[2.0, 2.0]--> spring The Method addend with 4.0--> 4.0--> spring The Method div begins with[2.0, 2.0]--> spring The Method divend with 1.0--> 1.0--> spring The Method mul begins with[2.0, 2.0]--> spring The Method mulend with 4.0--> 4.0--> spring The Method sub begins with[2.0, 2.0]--> spring The Method subend with 0.0--> 0.0
使用动态代理就解决了前面代码的不可行性,但是开发过程中还是不建议使用,原因如下:
一、实现过程还是比较麻烦的
二、一般程序员使用动态代理可能有问题
所以再考虑还有没有更简单的方式解决需求? 现在就该用到 AOP 了。
AOP 简介:
【1】 AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.
【2】 AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.
【3】 在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.
【4】 AOP 的好处:
- 每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
- 业务模块更简洁, 只包含核心业务代码.
现在再用图来区别 第一次 需求实现和 AOP 实现的不同之处
关于 AOP 的术语(生涩, 自行理解)
切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象通知(Advice): 切面必须要完成的工作目标(Target): 被通知的对象代理(Proxy): 向目标对象应用通知之后创建的对象连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 Calculator#add() 方法执行前的连接点,执行点为 Calculator#add(); 方位为该方法执行前的位置切点(pointcut):每个类都拥有多个连接点:例如 Calculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
阅读全文
0 0
- spring aop 基础
- Spring Aop基础使用
- Spring AOP---基础简介
- Spring AOP基础
- Spring Aop基础总结
- Spring AOP基础
- spring aop基础概念
- Spring AOP基础
- Spring中AOP基础
- Spring中的AOP基础
- SpringBoot2-spring基础-AOP
- Spring Aop基础
- Spring AOP 基础
- spring aop基础
- Spring基础-3-AOP
- Spring AOP基础
- Spring基础入门AOP
- [Spring]AOP基础
- 浅谈栈帧
- java排序 -- 堆排序
- Myeclipse中左边的项目目录调没了,怎么再让它显示出来
- Android Fragment 真正的完全解析(上)
- 实验七 静态查找表的查找
- Spring AOP基础
- python解析xml转化为csv
- 题目117:求逆序数
- VMware正常安装后仍然不能实现文件拖拽的原因
- keras 的LearningRateScheduler
- 高程第三章
- jQuery插件开发精品教程
- 特殊回文数
- jQuery金币兑换列表(单选自适应)