《Spring AOP学习总结之——通过动态代理实现AOP功能》

来源:互联网 发布:团队复制优化方案 编辑:程序博客网 时间:2024/06/05 12:07


   代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。


demo示例:

实现计算器的算法计算,如果是添加方法,则记录方法的基本日志,其它方法都一律不记录日志。

Demo示意图:



Demo实现:

1·计算器接口:

package com.dynamic.aop.helloworld;/** * 实现基本计算器的算术计算 * @author 贾丽敏 * */public interface ArithmeticCalculator {public int add(int i,int j);public int sub(int i,int j);public int mul(int i,int j);public int dev(int i,int j);}

          2·计算器接口实现类:

package com.dynamic.aop.helloworld;/** * 计算器接口实现类 * @author 贾丽敏 * */public class ArithmeticCalculatorImpl implements ArithmeticCalculator {public int add(int i, int j) {int result =i+j;return result;}public int sub(int i, int j) {int result =i-j;return result;}public int mul(int i, int j) {int result =i*j;return result;}public int dev(int i, int j) {int result =i/j;return result;}}

3·模拟日志的控制:

package com.dynamic.aop.helloworld;import java.lang.reflect.Method;import java.util.Arrays;/** * 定义日志切面 * @author 贾丽敏 * */public class LoggingAspect {public static void beginLogging(Method method,Object[] obj){System.out.println("the method "+ method.getName()+" begins with " + Arrays.asList(obj));}public static void endLogging(Method method,Object obj){System.out.println("the method "+ method.getName()+" end with " + Arrays.asList(obj));System.out.println("------------------华丽的分界面--------------------");}}


4·通过动态代理实现动态切入:
   
package com.dynamic.aop.helloworld;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 通过动态代理实现切入 * @author 贾丽敏 * */public class ArithmeticCalculatorProxy {private ArithmeticCalculator target;public ArithmeticCalculatorProxy(ArithmeticCalculator target) {super();this.target = target;}public ArithmeticCalculator getLoggingProxy(){ArithmeticCalculator proxy=null;//代理对象由哪一个类加载器负责加载ClassLoader loader=target.getClass().getClassLoader();//代理对象的类型,即其中有哪些方法Class[] interfaces=new Class[]{ArithmeticCalculator.class};InvocationHandler h=new InvocationHandler() {/** * proxy:正在返回的那个代理对象,一般情况下,在invoke方法中都不是用该对象 * method:被代理类(目标类)的方法 * args:调用被代理类(目标类)方法时,传入的参数 */public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {String methodName=method.getName();if (methodName.equals("add")){//如果调用目标方法名称为“add”则进行拦截//方法之前记录日志LoggingAspect.beginLogging(method,args);Object result=method.invoke(target, args);//调用目标类的目标方法//方法之后记录日志LoggingAspect.endLogging(method,result);return result;}else{Object result=method.invoke(target, args);//调用目标类的目标方法return result;}}};proxy=(ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);return proxy;}}

5·测试类:

package com.dynamic.aop.helloworld;import org.junit.Test;/** * 测试动态代理实现AOP切入 * @author 贾丽敏 * */public class test {@Testpublic void test() {ArithmeticCalculator target= new ArithmeticCalculatorImpl();ArithmeticCalculator proxy=new ArithmeticCalculatorProxy(target).getLoggingProxy();int result=0;result=proxy.add(1, 3);result=proxy.sub(5, 2);}}

6·执行结果:(满足条件的add方法添加了日志,sub方法则没有被拦截进行日志的记录)



Demo分析:


以上demo中,通过动态代理实现AOP的动态切入,我认为有以下几个关键点:

1·在客户端调用目标方法时,并不知道该方法是否要进行的日志的记录,也就是说目标类ArithmeticCalculator和日志记录类LoggingAspect之间并没有任何的关系。是代理类在中间起到了连接作用。

2·拦截器的存在很关键:拦截器体现了AOP"动态切入",执行代理类的方法时,拦截器实现了:在一定的条件下,对方法进行日志的记录。


Demo引发的思考:


1·拦截器的invoke方法在时候被调用的?

在客户端调用目标类的方法时,其实是调用的代理类的方法,当执行代理类的方法时执行了拦截器的invoke方法。

2·这个和Spring核心AOP有什么关系?

AOP的核心就是面向切面编程,即动态切入从而达到代码的灵活可用性。且AOP实现动态切入的核心就是动态代理。


Demo基本概念小总:


   这其实就是AOP中一些所谓的“晦涩难懂”的基本概念而已。

   先来看张图片(灵感来自于一篇朋友的博客《springAOP的基本概念》)





 

目标类:就是我们需要完成的基本功能的类,就像上面例子中的ArithmeticCalculator。

 目标方法:就是目标类中的方法

 切面(Aspect):就是和正常的业务逻辑无关的代码,像LoggingAspect

 通知(Advice):切面中的方法就是通知

 连接点(Join point):在客户端调用目标类的那个方法,那个方法就是连接点。

 切入点(PointCut):对目标类方法进行日志记录的条件:就是什么情况下才能让通知和目标方法结合在一起

 织入(Weaving):形成代理对象的过程就是织入;


这是自己初步的AOP的总结,之前的理解总是感觉有点浅显,如今再次回顾,同时借助于一个朋友的两篇博客,突然有一种很是简单的感觉。

接下来的系列博客正在编辑中,请多多支持。


阅读全文
0 0
原创粉丝点击