当前位置: 首页 > 科技观察

Java动态代理的实现机制

时间:2023-03-18 02:56:58 科技观察

1.概述  代理是一种设计模式,其目的是为其他对象提供代理以控制对某个对象的访问。代理类负责为委托类预处理消息。消息被委托类执行后过滤消息,转发消息,进行后续处理。为了保持行为的一致性,代理类和委托类通常实现相同的接口。  根据agent的创建周期,agent类可以分为两种:比如说,程序运行前代理类的.class文件已经存在。动态代理:利用反射机制在程序运行时动态创建生成。  下面先简单介绍一下动态代理的实现机制之前的静态代理。2.静态代理  上面说到,代理类和委托类一般要实现相同的接口。下面先定义接口:publicinterfaceService{publicvoidadd();}  委托类是接口的一个实现,定义如下:publicclassServiceImplimplementsService{publicvoidadd(){System.out.println("Adduser!");}}  如果我们想在委托类中添加一些日志操作,代理类可以定义如下:(){System.out.println("ServiceStart");service.add();System.out.println("ServiceEnd");}  写一个测试类:publicclassTestMain{publicstaticvoidmain(String[]args){ServiceserviceImpl=newServiceImpl();Serviceproxy=newServiceProxy(serviceImpl);proxy.add();}}  运行测试程序,结果如下:  从上面的代码可以看出,静态代理类只能服务于特定的接口。如果要为多种类型的对象提供服务,则必须代理每种类型的对象。我们会想到是否可以通过一个代理类来完成所有的代理功能,所以引入了动态代理的概念。3.动态代理  Java的动态代理主要涉及两个类,Proxy和InvocationHandler。  Proxy:提供一组静态方法,为一组接口动态生成代理类及其对象。//方法一:该方法用于获取指定代理对象关联的调用处理器staticInvocationHandlergetInvocationHandler(Objectproxy)//方法二:该方法用于获取指定类加载器关联的动态代理类的类对象和asetofinterfacesstaticClassgetProxyClass(ClassLoaderloader,Class[]interfaces)//方法三:该方法用于判断指定类对象是否为动态代理类staticbooleanisProxyClass(Classcl)//方法四:该方法用于指定一个类加载器,一组接口并调用处理器生成一个动态代理类实例动态代理类对象的方法调用,通常是在这个方法中实现对委托类的代理访问//这个方法是负责集中处理动态代理类上的所有方法调用。第一个参数是代理类实例,第二个参数是要调用的方法对象//第三个方法是调用参数。调用处理器根据这三个参数进行预处理或派发给委托类的实例启动并执行Objectinvoke(Objectproxy,Methodmethod,Object[]args)  实现Java的动态代理,具体有以下四个步骤:通过实现InvocationHandler接口创建自己的调用处理程序通过为Proxy类指定一个ClassLoader对象和一组接口创建动态代理类通过获取动态代理类的构造函数反射机制,它的最大参数类型是通过构造函数调用处理器类接口类型创建动态代理类实例,构造时调用处理器对象作为参数传入  接下来根据自己的动态代理实现对以上四步举例:  接口和接口实现类(即delegate类)和上面的静态代理代码一样,这里我们实现InvocationHandler接口创建自己的调用handlerpublicclassServiceHandleimplementsInvocationHandler{privateObjects;publicServiceHandle(Objects){this.s=s;}publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("ServiceStart");//invoke表示调用指定对象上的Method对象表示的底层方法,指定参数Objectresult=method.invoke(s,args);System.out.println("Serviceend");returnresult;}}  编写测试类:publicclassTestMain{publicstaticvoidmain(String[]args){Serviceservice=newServiceImpl();InvocationHandlerhandler=newServiceHandle(service);Services=(Service)Proxy.newProxyInstance(service.getClass().getClassLoader(),service.getClass().getInterfaces(),handler);s.add();}}  运行测试程序,结果和静态代理一样。我们可以看到上面的代码并没有我们之前提到的步骤2和步骤3,因为Prox的静态方法newProxyInstance已经帮我们封装好了这两个步骤。具体内部实现如下://通过Proxy为一组接口动态创建一个代理类的class对象,包括InterfaceinterfaceClassclazz=Proxy.getProxyClass(classLoader,newClass[]{Interface.class,...});//通过反射从生成的类对象中获取构造函数对象Constructorconstructor=clazz.getConstructor(newClass[]{InvocationHandler.class});//通过构造函数对象创建动态代理类实例InterfaceProxy=(Interface)constructor.newInstance(newObject[]{handler});  newProxyInstance函数内部实现为:publicstaticObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)throwsIllegalArgumentException  {//检查h不为空,否则抛出异常Objects.requireNonNull(h);//获取指定类加载器相关的代理类类型对象和一组接口finalClass[]intfs=interfaces.clone();//检查接口类对象是否对类加载器可见且与类加载器识别的接口类对象完全一致finalSecurityManagersm=System.getSecurityManager();if(sm!=null){checkProxyAccess(Reflection.getCallerClass(),loader,intfs);}//获取指定类加载器相关的代理类类型对象和一组接口Classcl=getProxyClass0(loader,intfs);try{if(sm!=null){checkNewProxyPermission(Reflection.getCallerClass(),cl);}//通过反射获取构造函数对象,生成代理类实例finalConstructorcons=cl.getConstructor(constructorParams);finalInvocationHandlerih=h;if(!Modifier.isPublic(cl.getModifiers())){AccessController.doPrivileged(newPrivilegedAction(){publicVoidrun(){cons.setAccessible(true);returnull;}});}returncons.newInstance(newObject[]{h});}catch(IllegalAccessException|InstantiationExceptione){thrownewInternalError(e.toString(),e);}catch(InvocationTargetExceptione){Throwablet=e.getCause();if(tinstanceofRuntimeException){throw(RuntimeException)t;}else{thrownInternalError(t.toString(),t);}}catch(NoSuchMethodExceptione){thrownewInternalError(e.toString(),e);} }四、模拟Proxy类的实现根据上面的原理介绍,我们可以自己模拟实现Proxy类:();for(Methodm:methods){methodStr+="@Override"+rt+"publicvoid"+m.getName()+"()"+rt+"{"+rt+"try{"+rt+"Methodmd="+inface.getName()+".class.getMethod(\""+m.getName()+"\");"+rt+"h.invoke(this,md);"+rt+"}catch(Exceptione){e.printStackTrace();}"+rt+"}";}Stringsrc="packagetest;"+rt+"importjava.lang.reflect.Method;"+rt+"publicclassServiceImpl2implements"+inface.getName()+rt+"{"+rt+"publicServiceImpl2(InvocationHandleh)"+rt+"{"+rt+"this.h=h;"+rt+"}"+rt+"test.InvocationHandleh;"+rt+methodStr+"}";StringfileName="d:/src/测试/服务viceImpl2.java";//compilecompile(src,fileName);//loadintomemoryandcreateinstanceObjectm=loadMemory(h);returnm;}privatestaticvoidcompile(Stringsrc,StringfileName)throwsIOException{Filef=newFile(fileName);FileWriterfileWriter=newFileWriter(f);fileWriter.write(src);fileWriter.flush();fileWriter.close();//获取本平台提供的Java编译器JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();//获取标准文件管理器的新实例StandardJavaFileManagerfileManager=compiler.getStandardFileManager(null,null,null);//获取代表给定文件的文件对象Iterableunits=fileManager.getJavaFileObjects(fileName);//使用给定的组件和参数创建编译任务的futureCompilationTask=compiler.getTask(null,fileManager,null,null,null,units);//执行本次编译任务t.call();fileManager.close();}privatestaticObjectloadMemory(InvocationHandleh)throwsMalformedURLException,ClassNotFoundException,NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetExceptions=url[URLnewURL[]{newURL("file:/"+"d:/src/")};//来自路径d:/src/加载类和资源URLClassLoaderul=newURLClassLoader(urls);Classc=ul.loadClass("test.ServiceImpl2");//返回Class对象表示的类的指定公共构造函数。Constructorctr=c.getConstructor(InvocationHandle.class);//使用Constructor对象ctr表示的构造函数创建构造函数声明类的新实例,并用指定的初始化参数初始化该实例Objectm=ctr.newInstance(h);returnm;}}五、总结1、所谓动态代理就是这样一个类,它是在运行时生成的类。生成它的时候,必须给它提供一组接口,然后改类声明它已经实现了。这些接口,但实际上它不会为你做实质性的工作,而是根据你在生成实例时提供的参数handler(即InvocationHandler接口的实现类),由Handler来接管实际的工作。  2。Proxy被设计成只能支持接口代理。Java的继承机制注定了动态代理类无法实现类的动态代理,因为多重继承在Java中本来就是不切实际的。

最新推荐
猜你喜欢