利用Java的反射与代理实现IOC模式.docx
- 文档编号:11151693
- 上传时间:2023-05-29
- 格式:DOCX
- 页数:19
- 大小:21.69KB
利用Java的反射与代理实现IOC模式.docx
《利用Java的反射与代理实现IOC模式.docx》由会员分享,可在线阅读,更多相关《利用Java的反射与代理实现IOC模式.docx(19页珍藏版)》请在冰点文库上搜索。
利用Java的反射与代理实现IOC模式
在Java中,其反射和动态代理机制极其强大,我们可以通过其反射机制在运行时获取信息。
而代理是一种基本的设计模式,它是一种为了提供额外的或不同的操作而插入到真实对象中的某个对象。
而Java的动态代理在代理上更进一步,既能动态的创建代理对象,又能动态的调用代理方法。
Java的反射和动态代理机制,使Java变得更加强大。
Spring框架这几年风头正劲,虽然使用者众多,但真正了解其内部实现原理的朋友却并不是很多。
其实,了解它的内部实现机制和设计思想是很有必要的大家都知道,Spring框架的IOC和AOP部分功能强大,很值得我们学习。
那么让我们在这两篇文章中分别详细的学习IOC和AOP的实现吧。
在本文中,主要讲述的是用Java的反射机制实现IOC。
下面,让我们开始IOC之旅吧!
一. Java反射机制概述与初探
Java的反射机制是Java语言的一个重要特性,Java具有的比较突出的动态机制就是反射(reflection)。
通过它,我们可以获取如下信息:
1) 在运行时判断任意一个对象所属的类;
2) 在运行时获取类的对象;
3) 在运行时获得类所具有的成员变量和方法等。
下面让我们通过调用一个JavaReflectionAPI的演示实例来见识一下反射机制的强大。
首先在IDE中建立名为reflection_proxy的Java工程,并建立存放源文件的目录src,并在src目录下分别建立org.amigo.reflection目录和org.amigo.proxy目录来分别存放代理和反射的实例。
我们在reflection目录下建立ReflectionTest.java文件,在该文件中编写代码来演示JavaReflectionAPI的使用。
该类的代码如下所示:
packageorg.amigo.reflection;
importjava.awt.Button;
importjava.lang.reflect.Method;
importjava.util.Hashtable;
/**
*初探Java的反射机制.
*@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-2-上午10: 13: 48 */ PublicclassReflectionTest{ /** *@paramargs */ publicstaticvoidmain(String[]args)throwsException{ ReflectionTestreflection=newReflectionTest(); reflection.getNameTest(); System.out.println(""); reflection.getMethodTest(); } /** *Class的getName()方法测试. *@throwsException */ publicvoidgetNameTest()throwsException{ System.out.println("===========begingetNameTest============"); Stringname="阿蜜果"; Classcls=name.getClass(); System.out.println("String类名: "+cls.getName()); Buttonbtn=newButton(); ClassbtnClass=btn.getClass(); System.out.println("Button类名: "+btnClass.getName()); ClasssuperBtnClass=btnClass.getSuperclass(); System.out.println("Button的父类名: "+superBtnClass.getName()); ClassclsTest=Class.forName("java.awt.Button"); System.out.println("clsTestname: "+clsTest.getName()); System.out.println("===========endgetNameTest============"); } /** *Class的getMethod()方法测试. *@throwsException */ PublicvoidgetMethodTest()throwsException{ System.out.println("===========begingetMethodTest=========="); Classcls=Class.forName("org.amigo.reflection.ReflectionTest"); Classptypes[]=newClass[2]; ptypes[0]=Class.forName("java.lang.String"); ptypes[1]=Class.forName("java.util.Hashtable"); Methodmethod=cls.getMethod("testMethod",ptypes); Objectargs[]=newObject[2]; args[0]="hello,mydear! "; Hashtable ht.put("name","阿蜜果"); args[1]=ht; StringreturnStr=(String)method.invoke(newReflectionTest(),args); System.out.println("returnStr="+returnStr); System.out.println("===========endgetMethodTest=========="); } publicStringtestMethod(Stringstr,Hashtableht)throwsException{ StringreturnStr="返回值"; System.out.println("测试testMethod()方法调用"); System.out.println("str="+str); System.out.println("名字="+(String)ht.get("name")); System.out.println("结束testMethod()方法调用"); returnreturnStr; } } 运行该例,可在控制台看到如下内容: ===========begingetNameTest============ String类名: java.lang.String Button类名: java.awt.Button Button的父类名: java.awt.Component clsTestname: java.awt.Button ===========endgetNameTest============ ===========begingetMethodTest========== 测试testMethod()方法调用 str=hello,mydear! 名字=阿蜜果 结束testMethod()方法调用 returnStr=返回值 ===========endgetMethodTest========== 分析运行结果,我们可以发现,Java的反射机制使得我们在运行时能够判断一个对象所属的类,获取对象的方法并得其进行调用,并获取方法的返回结果等功能。 二、 IOC使用的背景 在我们日常的设计中,类与类之间存在着千丝万缕的关系,如果两个类存在着强耦合关系,那么在维护时,一个类的修改很可能会牵动另一个类的关联修改,从而使得我们的维护工作步履维艰。 下面让我们来看这样的一个强耦合反面例子。 首先我们建立一个Chinese.java类,该类的sayHelloWorld(Stringname)方法,用中文对名为name的人问好,其内容如下: packageorg.amigo.reflection; /** *中国人类. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-2-上午10: 37: 17 */ publicclassChinese{ /** *用中文对某人问好. *@paramname姓名 */ publicvoidsayHelloWorld(Stringname){ StringhelloWorld="你好,"+name; System.out.println(helloWorld); } } 下面我们接着建立一个American.java类,该类的sayHelloWorld(Stringname)方法,用英文对名为name的人问好,其内容如下: packageorg.amigo.reflection; /** *美国人类. *@author xiexingxing1121@">AmigoXie *@version1.0 *Creationdate: 2007-10-2-上午10: 41: 27 */ publicclassAmerican{ /** *用英文对某人问好. *@paramname姓名 */ publicvoidsayHelloWorld(Stringname){ StringhelloWorld="Hello,"+name; System.out.println(helloWorld); } } 最后我们编写一个测试类对这两个类的sayHelloWorld(Stringname)方法进行测试,下面是该类的内容: packageorg.amigo.reflection; /** *HelloWorld测试. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-2-上午10: 45: 13 */ publicclassHelloWorldTest{ /** *测试Chinese和American的sayHelloWorld()方法. *@paramargs *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-2-上午10: 43: 51 */ publicstaticvoidmain(String[]args){ Chinesechinese=newChinese(); chinese.sayHelloWorld("阿蜜果"); Americanamerican=newAmerican(); american.sayHelloWorld("Amigo"); } } 观察HelloWorldTest我们可以很清楚的看到,该类与Chinese.java类和American.java类都存在强耦合关系。 上面的例子让我们想到的是在N年以前,当我们需要某个东西时,我们一般是自己制造。 但是当发展到了一定的阶段后,工厂出现了,我们可以工厂中购买我们需要的东西,这极大的方便了我们。 在上例中,我们都是通过new来创建新的对象,在开发中,这种强耦合关系是我们所不提倡的,那么我们应该如何来实现这个例子的解耦呢? 我们接着想到了使用工厂模式,我们需要新建一个工厂类来完成对象的创建,并采用依赖接口的方式,此时需要对代码进行如下修改: 首先建立接口类Human.java,其内容如下。 packageorg.amigo.reflection; /** *人类接口类. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-2-上午11: 04: 56 */ publicinterfaceHuman{ /** *对某人问好. *@paramname姓名 */ publicvoidsayHelloWorld(Stringname); } 并将American.java类和Chinese.java类改为实现该接口,即类头分别改成: publicclassAmericanimplementsHuman和publicclassChineseimplementsHuman。 接着编写HumanFactory.java工厂类,其内容为: packageorg.amigo.reflection; /** *工厂类. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-2-上午11: 09: 30 */ publicclassHumanFactory{ /** *通过类型字段获取人的相应实例 *@paramtype类型 *@return返回相应实例 */ publicHumangetHuman(Stringtype){ if("chinese".equals(type)){ returnnewChinese(); }else{ returnnewAmerican(); } } } 最后我们还需要修改测试类HelloWorld.java类,修改后的内容如下: packageorg.amigo.reflection; /** *HelloWorld测试. *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-2-上午10: 45: 13 */ publicclassHelloWorldTest{ /** *测试sayHelloWorld()方法. *@paramargs *@author xiexingxing1121@">AmigoXie *Creationdate: 2007-10-2-上午10: 43: 51 */ publicstaticvoidmain(String[]args){ HumanFactoryfactory=newHumanFactory(); Humanhuman1=factory.getHuman("chinese"); human1.sayHelloWorld("阿蜜果"); Humanhuman2=factory.getHuman("american"); human2.sayHelloWorld("Amigo"); } } 观察此例我们可以看到,该类不再与具体的实现类Chinese和American存在耦合关系,而只是与它们的接口类Human存在耦合关系,具体对象的获取只是通过传入字符串来获取,很大程度上降低了类与类之间的耦合性。 但是我们还是不太满足,因为还需要通过chinese和american在类中获取实例,那么当我们需要修改时实现时,我们还需要在类中修改这些字符串,那么还有没有更好的办法呢? 让我们在下节中进行继续探讨。 三. IOC粉墨登场 IOC(InverseofControl)可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”。 在Spring中,通过IOC可以将实现类、参数信息等配置在其对应的配置文件中,那么当需要更改实现类或参数信息时,只需要修改配置文件即可,这种方法在上例的基础上更进一步的降低了类与类之间的耦合。 我们还可以对某对象所需要的其它对象进行注入,这种注入都是在配置文件中做的,Spring的IOC的实现原理利用的就是Java的反射机制,Spring还充当了工厂的角色,我们不需要自己建立工厂类。 Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象。 下面让我们看看如下的模拟Spring的bean工厂类: packageorg.amigo.reflection; 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-6-上午10: 04: 41 */ publicclassBeanFactory{ privateMap /** *bean工厂的初始化. *@paramxmlxml配置文件 */ publicvoidinit(Stringxml){ try{ //读取指定的配置文件 SAXReaderreader=newSAXReader(); ClassLoaderclassLoader=Thread.currentThread().getContextClassLoader(); //从class目录下获取指定的xml文件 InputStreamins=classLoader.getResourceAsStream(xml); Documentdoc=reader.read(ins); Elementroot=doc.getRootElement(); Elementfoo; //遍历bean for(Iteratori=root.elementIterator("bean");i.hasNext();){ foo=(Element)i.next(); //获取bean的属性id和class Attributeid=foo.attribute("id"); Attributecls=foo.attribute("class"); //利用Java反射机制,通过class的名称获取Class对象 Classbean=Class.forName(cls.g
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 利用 Java 反射 代理 实现 IOC 模式