标签:style blog io color ar os 使用 java sp
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 @Override 13 public int sub(int i, int j) { 14 int result = i - j; 15 return result; 16 } 17 18 @Override 19 public int mul(int i, int j) { 20 int result = i * j; 21 return result; 22 } 23 24 @Override 25 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 @Override 15 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 @Override 23 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 @Override 31 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 @Override 33 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的具体用法还请参考本系列的后续文章......
标签:style blog io color ar os 使用 java sp
原文地址:http://www.cnblogs.com/dreamfree/p/4093768.html