java动态代理实现AOP.docx
- 文档编号:30712332
- 上传时间:2023-08-19
- 格式:DOCX
- 页数:17
- 大小:20.23KB
java动态代理实现AOP.docx
《java动态代理实现AOP.docx》由会员分享,可在线阅读,更多相关《java动态代理实现AOP.docx(17页珍藏版)》请在冰豆网上搜索。
java动态代理实现AOP
在上一篇文章中,我们讲述了利用Java的反射机制中实现Spring中的IOC,在本文中,我们将更进一步,讲述用Java的反射和动态代理机制来实现Spring的AOP。
一.AOP概述
AOP(Aspect Oriented Programing),即面向切面编程,它主要用于日志记录、性能统计、安全控制、事务处理、异常处理等方面。
它的主要意图就要将日志记录,性能统计,安全控制、事务处理、异常处理等等代码从业务逻辑代码中清楚地划分出来。
通过对这些行为的分离,我们希望可以将它们独立地配置到业务逻辑方法中,而要改变这些行为的时候也不需要影响到业务逻辑方法代码。
下面让我们来看一个利用AOP来实现日志记录的例子,在没有使用AOP之前,我们的代码如下面所讲述。
下面这段代码为业务的接口类代码:
packageorg.amigo.proxy;
/**
*业务逻辑类接口.
*@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-上午09: 09: 53 */ publicinterfaceBusinessObj{ /** *执行业务. */ publicvoidprocess(); } BusinessObj接口的某个实现类代码如下: packageorg.amigo.proxy; /** *业务逻辑对象实现类. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-上午09: 11: 49 */ publicclassBusinessObjImplimplementsBusinessObj{ /** *执行业务. */ publicvoidprocess(){ try{ System.out.println("beforeprocess"); System.out.println("执行业务逻辑"); System.out.println("afterprocess"); }catch(Exceptione){ System.err.println("发生异常: "+e.toString()); } } } 在上例中我们可以看到,在执行业务方法前、执行业务方法后以及异常发生时的日志记录,我们都是通过在对应的类中写入记录日志的代码来实现的,当有这种日志记录需求的业务逻辑类不断增多时,将会给我们的维护带来很大困难,而且,在上面的例子中,日志代码和业务逻辑代码混合在一起,为日后的维护工作又抹上了一层“恐怖”色彩。 按照AOP的思想,我们首先需要寻找一个切面,在这里我们已经找到,即在业务逻辑执行前后以及异常发生时,进行相应的日志记录。 我们需要将这部分日志代码放入一个单独的类中,以便为以后的修改提供方便。 我们在截获某个业务逻辑方法时,可以采用Java的动态代理机制来实现。 在下节中我们将重点讲述Java的动态代理机制。 二.Java的动态代理机制 代理模式是常用的Java设计模式。 代理类主要负责为委托类预处理消息、过滤信息、把消息转发给委托类,以及事后处理信息等。 动态代理类不仅简化了编程工作,而且提高了软件系统的扩展性和可维护性。 我们可以通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器,然后通过java.lang.reflect.Proxy得到一个代理对象,通过这个代理对象来执行业务逻辑方法,在业务逻辑方法被调用的同时,自动调用会执行处理器。 下面让我们来创建一个日志拦截器类LogInterceptor.java文件,该类实现java.lang.reflect.InvocationHandler接口,其内容如下所示: packageorg.amigo.proxy; importjava.lang.reflect.InvocationHandler; importjava.lang.reflect.Method; importjava.lang.reflect.Proxy; /** *日志拦截器,用来进行日志处理. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-上午09: 31: 44 */ publicclassLogInterceptorimplementsInvocationHandler{ privateObjectdelegate; /** *构造函数,设置代理对象. */ publicLogInterceptor(Objectdelegate){ this.delegate=delegate; } /** *方法的调用. *@paramproxy *@parammethod对应的方法 *@paramargs方法的参信息 *@return返回操作结果对象 *@throwsThrowable */ publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{ Objectresult=null; try{ System.out.println("beforeprocess"+method); //调用代理对象delegate的method方法,并将args作为参数信息传入 result=method.invoke(delegate,args); System.out.println("afterprocess"+method); }catch(Exceptione){ System.err.println("发生异常: "+e.toString()); } returnresult; } /** *测试方法. *@paramargs *@throwsException */ publicstaticvoidmain(String[]args)throwsException{ BusinessObjobj=newBusinessObjImpl(); //创建一个日志拦截器 LogInterceptorinterceptor=newLogInterceptor(obj); //通过Proxy类的newProxyInstance(...)方法来获得动态的代理对象 BusinessObjproxy=(BusinessObj)Proxy.newProxyInstance( BusinessObjImpl.class.getClassLoader(), BusinessObjImpl.class.getInterfaces(), interceptor); //执行动态代理对象的业务逻辑方法 proxy.process(); } } 此时还需要对BusinessObj的实现类BusinessObjImpl类进行修改,去掉其日志记录等内容,修改后的文件如下: packageorg.amigo.proxy; /** *业务逻辑对象实现类. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-上午09: 11: 49 */ publicclassBusinessObjImplimplementsBusinessObj{ /** *执行业务. */ publicvoidprocess(){ System.out.println("执行业务逻辑"); } } 运行LogInterceptor类我们可以发现,它实现了前面所需要的功能,但是很好的将业务逻辑方法的代码和日志记录的代码分离开来,并且所有的业务处理对象都可以利用该类来完成日志的记录,防止了重复代码的出现,增加了程序的可扩展性和可维护性,从而提高了代码的质量。 那么Spring中的AOP的实现是怎么样的呢? 接着让我们来对Spring的AOP进行探讨,了解其内部实现原理。 三.Spring中AOP的模拟实现 在学习了Java的动态代理机制后,我们在本节中将学习Java的动态代理机制在Spring中的应用。 首先我们创建一个名为AopHandler的类,该类可生成代理对象,同时可以根据设置的前置或后置处理对象分别在方法执行前后执行一些另外的操作,该类的内容如下所示: packageorg.amigo.proxy; importjava.lang.reflect.InvocationHandler; importjava.lang.reflect.Method; importjava.lang.reflect.Proxy; /** *AOP处理器. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-上午10: 13: 28 */ publicclassAopHandlerimplementsInvocationHandler{ //需要代理的目标对象 privateObjecttarget; //方法前置顾问 AdvisorbeforeAdvisor; //方法后置顾问 AdvisorafterAdvisor; /** *设置代理目标对象,并生成动态代理对象. *@paramtarget代理目标对象 *@return返回动态代理对象 */ publicObjectsetObject(Objecttarget){ //设置代理目标对象 this.target=target; //根据代理目标对象生成动态代理对象 Objectobj=Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(),this); returnobj; } /** *若定义了前置处理,则在方法执行前执行前置处理, *若定义了后置处理,则在方法调用后调用后置处理. *@paramproxy代理对象 *@parammethod调用的业务方法 *@paramargs方法的参数 *@return返回结果信息 *@throwsThrowable */ publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{ //进行业务方法的前置处理 if(beforeAdvisor! =null){ beforeAdvisor.doInAdvisor(proxy,method,args); } //执行业务方法 Objectresult=method.invoke(target,args); //进行业务方法的后置处理 if(afterAdvisor! =null){ afterAdvisor.doInAdvisor(proxy,method,args); } //返回结果对象 returnresult; } /** *设置方法的前置顾问. *@paramadvisor方法的前置顾问 */ publicvoidsetBeforeAdvisor(Advisoradvisor){ this.beforeAdvisor=advisor; } /** *设置方法的后置顾问. *@paramadvisor方法的后置顾问 */ publicvoidsetAfterAdvisor(Advisoradvisor){ this.afterAdvisor=advisor; } } 在上类中,前置和后置顾问对象都继承Advisor接口,接下来让我们来看看顾问接口类的内容,该类定义了doInAdvisor(Objectproxy,Methodmethod,Object[]args)方法,如下所示: packageorg.amigo.proxy; importjava.lang.reflect.Method; /** * *顾问接口类. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-上午10: 21: 18 */ publicinterfaceAdvisor{ /** *所做的操作. */ publicvoiddoInAdvisor(Objectproxy,Methodmethod,Object[]args); } BeforeMethodAdvisor和AfterMethodAdvisor都实现了Advisor接口,分别为方法的前置顾问和后置顾问类。 BeforeMethodAdvisor.java文件(前置顾问类)的内容如下所示: packageorg.amigo.proxy; importjava.lang.reflect.Method; /** * *方法前置顾问,它完成方法的前置操作. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-上午10: 19: 57 */ publicclassBeforeMethodAdvisorimplementsAdvisor{ /** *在方法执行前所进行的操作. */ publicvoiddoInAdvisor(Objectproxy,Methodmethod,Object[]args){ System.out.println("beforeprocess"+method); } } AfterMethodAdvisor.java文件(后置顾问类)的内容如下所示: packageorg.amigo.proxy; importjava.lang.reflect.Method; /** * *方法的后置顾问,它完成方法的后置操作. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-上午10: 20: 43 */ publicclassAfterMethodAdvisorimplementsAdvisor{ /** *在方法执行后所进行的操作. */ publicvoiddoInAdvisor(Objectproxy,Methodmethod,Object[]args){ System.out.println("afterprocess"+method); } } 这两个类分别在方法执行前和方法执行后做一些额外的操作。 对于在配置文件中对某个bean配置前置或后置处理器,我们可以在bean中增加两个属性aop和aopType,aop的值为对应的前置顾问类或后置顾问类的名称,aopType用于指明该顾问类为前置还是后置顾问,为before时表示为前置处理器,为after时表示为后置处理器,这时候我们需要修改上一篇文章中的BeanFactory.java这个文件,添加其对aop和aopType的处理,修改后的该文件内容如下: packageorg.amigo.proxy; importjava.io.InputStream; importjava.lang.reflect.Method; importjava.util.HashMap; importjava.util.Iterator; importjava.util.Map; importorg.dom4j.Attribute; importorg.dom4j.Document; importorg.dom4j.Element; importorg.dom4j.io.SAXReader; /** *bean工厂类. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-7-下午04: 04: 34 */ publicclassBeanFactory{ privateMap /** *bean工厂的初始化. *@paramxmlxml配置文件 */ publicvoidinit(Stringxml){ try{ //读取指定的配置文件 SAXReaderreader=newSAXReader(); ClassLoaderclassLoader=Thread.currentThread().getContextClassLoader(); InputStreamins=classLoader.getResourceAsStream(xml); Documentdoc=reader.read(ins); Elementroot=doc.getRootElement(); Elementfoo; //创建AOP处理器 AopHandleraopHandler=newAopHandler(); //遍历bean for(Iteratori=root.elementIterator("bean");i.hasNext();){ foo=(Element)i.next(); //获取bean的属性id、class、aop以及aopType Attributeid=foo.attribute("id"); Attributecls=foo.attribute("class"); Attributeaop=foo.attribute("aop"); AttributeaopType=foo.attribute("aopType"); //配置了aop和aopType属性时,需进行拦截操作 if(aop! =null&&aopType! =null){ //根据aop字符串获取对应的类 ClassadvisorCls=Class.forName(aop.getText()); //创建该类的对象 Advisoradvisor=(Advisor)advisorCls.newInstance(); //根据aopType的类型来设置前置或后置顾问 if("before".equals(aopType.getText())){ aopHandler.setBeforeAdvisor(advisor); }elseif("after".equals(aopType.getText())){ aopHandler.setAfterAdvisor(advisor); } } //利用Java反射机制,通过class的名称获取Class对象 Classbean=Class.forName(cls.getText()); //获取对应class的信息 java.beans.BeanInfoinfo=java.beans.Introspector.getBeanInfo(bean); //获取其属性描述 java.beans.PropertyDescriptorpd[]=info.getPropertyDescriptors(); //设置值的方法 MethodmSet=null; //创建一个对象 Objectobj=bean.newInstance(); //遍历该bean的property属性 for(Iteratorite=foo.elementIterator("property");ite.hasNext();){ Elementfoo2=(Element)ite.next(); //获取该property的name属性 Attributename=foo2.attribute("name"); Stringvalue=null; //获取该property的子元素value的值 for(Iteratorite1=foo2.elementIterator("value");ite1.hasNext();){ Elementnode=(Element)ite1.next(); value=node.getText(); break; } for(intk=0;k if(pd[k].getName().equalsIgnoreCase(name.getText())){ mSet=pd[k].getWriteMethod(); //利用Java的反射极致调用对象的某个set方法,并将值设置进去 mSet.invoke(obj,value); } } } //为对象增加前置或后置顾问 obj=(Object)aopHandler.setObject(obj); //将对象放入beanMap中,其中key为id值,value为对象 beanMap.put(id.getText(),obj); } }catch(Exceptione){ System.out.println(e.toString()); } } /** *通过bean的id获取bean的对象. *@parambeanNamebean的id *@return返回对应对象 */ publicObjectgetBean(StringbeanName){ Objectobj=beanMap.get(beanName); returnobj;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 动态 代理 实现 AOP