15Spring AOP基础
为什么需要AOP?
先来看一段代码:
package com.cn.spring.aop.helloworld; //加减乘除的接口类 public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); }
package com.cn.spring.aop.helloworld; //实现类 public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { int result = i + j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; } }
现在问题来了:
现在需要在程序执行期间追踪正在发生的活动?
代码如下:
package com.cn.spring.aop.helloworld; //实现类 public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { System.out.println("The method add begins with[" + i + "," + j + "]"); int result = i + j; System.out.println("The method add ends with[" + i + "," + j + "]"); return result; } @Override public int sub(int i, int j) { System.out.println("The method sub begins with[" + i + "," + j + "]"); int result = i - j; System.out.println("The method sub ends with[" + i + "," + j + "]"); return result; } @Override public int mul(int i, int j) { System.out.println("The method mul begins with[" + i + "," + j + "]"); int result = i * j; System.out.println("The method mul ends with[" + i + "," + j + "]"); return result; } @Override public int div(int i, int j) { System.out.println("The method div begins with[" + i + "," + j + "]"); int result = i / j; System.out.println("The method div ends with[" + i + "," + j + "]"); return result; } }
如果还希望计算器的加减乘除只能处理整数的运算呢,又需要在ArithmeticCalculatorImpl 实现类中添加代码进行验证,每添加一个需求,都要去添加类似的代码。
使得代码冗余且维护性低。
那如何用AOP来解决呢?
AOP是使用代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
先来看下代理是如何来实现的:
package com.cn.spring.aop.helloworld; //加减乘除的接口类 public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); }
package com.cn.spring.aop.helloworld; //实现类 public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { int result = i + j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; } }
package com.cn.spring.aop.helloworld; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; public class ArithmeticCalculatorLoggingProxy { //要代理的对象 private ArithmeticCalculator target; public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) { this.target = target; } public ArithmeticCalculator getLoggingProxy() { ArithmeticCalculator proxy = null; //代理对象由哪一个类加载器负责加载 ClassLoader loader = target.getClass().getClassLoader(); //代理对象的类型,即其中有哪些方法 Class[] interfaces = new Class[]{ArithmeticCalculator.class}; InvocationHandler handler = new InvocationHandler() { /** * * @param proxy 正在返回的那个代理对象,一般情况下,在invoke方法中都不使用该对象 * @param method 正在被调用的方法 * @param args 调用方法时,传入的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); System.out.println("The methed " + methodName + "begins with " + Arrays.asList(args)); Object result = method.invoke(target, args); System.out.println("The methed " + methodName + "end with " + Arrays.asList(args)); return result; } }; proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, handler); return proxy; } }
package com.cn.spring.aop.helloworld; /** * Created by jecyhw on 2015/6/20. */ public class Main { public static void main(String[] args) { ArithmeticCalculator target = new ArithmeticCalculatorImpl(); ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy(); int result = proxy.add(1, 2); System.out.println("-->" + result); result = proxy.sub(1, 2); System.out.println("-->" + result); result = proxy.mul(1, 2); System.out.println("-->" + result); result = proxy.div(1, 2); System.out.println("-->" + result); } }
Spring AOP基础:
- AOP(Aspect-Oriented Programming 面向切面编程)是一种新的方法论,是对传统OOP(Object-Oriented Programming 面向对象编程)的补充
- AOP的主要编程对象是切面(aspect),而切面模块化横切关注点
- 在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的对象(切面)里。
- AOP的好处:每个事物逻辑位于一个位置,代码不分散,便于维护和升级;业务模块更简洁,只包含核心业务代码。
- 切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
- 通知(Advice):切面必须要完成的工作
- 目标(Target):被通知的对象
- 代理(Proxy):向目标对象应用通知之后创建的对象
- 连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等,连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位,例如ArithmeticCalculator#add()方法执行前的连接点,执行点为 ArithmeticCalculator#add();方法为该方法执行前的位置
- 切点(pointcut):每个类都拥有多个连接点:例如ArithmeticCalculator的所有方法实际上都是连接点,即连接点是程序类中客观存在的事物。AOP通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件。