Java动态代理的实现机制.docx

上传人:牧羊曲112 文档编号:3159573 上传时间:2023-03-11 格式:DOCX 页数:13 大小:41.19KB
返回 下载 相关 举报
Java动态代理的实现机制.docx_第1页
第1页 / 共13页
Java动态代理的实现机制.docx_第2页
第2页 / 共13页
Java动态代理的实现机制.docx_第3页
第3页 / 共13页
Java动态代理的实现机制.docx_第4页
第4页 / 共13页
Java动态代理的实现机制.docx_第5页
第5页 / 共13页
亲,该文档总共13页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《Java动态代理的实现机制.docx》由会员分享,可在线阅读,更多相关《Java动态代理的实现机制.docx(13页珍藏版)》请在三一办公上搜索。

1、Java动态代理的实现机制一、概述 代理是一种设计模式,其目的是为其他对象提供一个代理以控制对某个对象的访问,代理类负责为委托类预处理消息,过滤消息并转发消息以及进行消息被委托类执行后的后续处理。为了保持行为的一致性,代理类和委托类通常会实现相同的接口。 按照代理的创建时期,代理类可分为两种: 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,也就是说在程序运行前代理类的.class文件就已经存在。 动态代理:在程序运行时运用反射机制动态创建生成。 下面在将动态代理的实现机制之前先简单介绍一下静态代理。 二、静态代理 上面说过,代理类和委托类一般都要实现相同的接口,下面先定义这个

2、接口: 1. public interface Service 2. 3. public void add; 4. 委托类作为接口的一种实现,定义如下: 1. public class ServiceImpl implements Service 2. 3. public void add 4. 5. System.out.println(添加用户!); 6. 7. 8. 假如我们要对委托类加一些日志的操作,代理类可做如下定义: 1. public class ServiceProxy implements Service 2. 3. private Service service; 4. p

3、ublic ServiceProxy(Service service) 5. 6. super; 7. this.service = service; 8. 9. public void add 10. 11. System.out.println(服务开始); 12. service.add; 13. System.out.println(服务结束); 14. 15. 编写测试类: 1. public class TestMain 2. 3. public static void main(String args) 4. 5. Service serviceImpl=new ServiceI

4、mpl; 6. Service proxy=new ServiceProxy(serviceImpl); 7. proxy.add; 8. 9. 运行测试程序,结果如下图: 从上面的代码可以看到,静态代理类只能为特定的接口服务,如果要服务多类型的对象,就要为每一种对象进行代理。我们就会想是否可以通过一个代理类完成全部的代理功能,于是引入的动态代理的概念。 三、动态代理 Java的动态代理主要涉及两个类,Proxy和InvocationHandler。 Proxy:提供了一组静态方法来为一组接口动态地生成代理类及其对象。 1. / 方法 1: 该方法用于获取指定代理对象所关联的调用处理器 2.

5、static InvocationHandler getInvocationHandler(Object proxy) 3. 4. / 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 5. static Class getProxyClass(ClassLoader loader, Class interfaces) 6. 7. / 方法 3:该方法用于判断指定类对象是否是一个动态代理类 8. static boolean isProxyClass(Class cl) 9. 10. / 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 11.

6、 static Object newProxyInstance(ClassLoader loader, Class interfaces,InvocationHandler h) InvocationHandler:它是调用处理器接口,自定义了一个invok方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问 1. / 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象/ 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行 2. Object invoke(Object prox

7、y, Method method, Object args) 实现Java的动态代理,具体有以下四个步骤: 1. 通过实现InvocationHandler接口创建自己的调用处理器 2. 通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类 3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器类接口类型 4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入 下面根据上述的四个步骤来实现自己的动态代理的示例: 接口和接口的实现类(即委托类)跟上面静态代理的代码一样,这里我们来实现InvocationHandler接口创建自

8、己的调用处理器 1. public class ServiceHandle implements InvocationHandler 2. 3. private Object s; 4. 5. public ServiceHandle(Object s) 6. 7. this.s = s; 8. 9. public Object invoke(Object proxy, Method method, Object args) 10. throws Throwable 11. 12. System.out.println(服务开始); 13. /invoke表示对带有指定参数的指定对象调用由此

9、Method 对象表示的底层方法 14. Object result=method.invoke(s, args); 15. System.out.println(服务结束); 16. return result; 17. 18. 编写测试类: 1. public class TestMain 2. 3. public static void main(String args) 4. 5. Service service=new ServiceImpl; 6. InvocationHandler handler=new ServiceHandle(service); 7. Service s=

10、(Service) Proxy.newProxyInstance(service.getClass.getClassLoader, service.getClass.getInterfaces, handler); 8. s.add; 9. 10. 运行测试程序,结果同静态代理。我们可以看到上述代码并没有我们之前说的步骤2和3,这是因为Prox的静态方法newProxyInstance已经为我们封装了这两个步骤。具体的内部实现如下: 1. / 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象 2. Class clazz = Proxy.getProxyC

11、lass(classLoader, new Class Interface.class, . ); 3. 4. / 通过反射从生成的类对象获得构造函数对象 5. Constructor constructor = clazz.getConstructor(new Class InvocationHandler.class ); 6. 7. / 通过构造函数对象创建动态代理类实例 8. Interface Proxy = (Interface)constructor.newInstance(new Object handler ); newProxyInstance函数的内部实现为: 1. pu

12、blic static Object newProxyInstance(ClassLoader loader, Class interfaces,InvocationHandler h)throws IllegalArgumentException 2. 3. /检查h不为空,否则抛异常 4. Objects.requireNonNull(h); 5. /获得与制定类装载器和一组接口相关的代理类类型对象 6. final Class intfs = interfaces.clone; 7. 8. /检查接口类对象是否对类装载器可见并且与类装载器所能识别的接口类对象是完全相同的 9. final

13、 SecurityManager sm = System.getSecurityManager; 10. if (sm != null) 11. 12. checkProxyAccess(Reflection.getCallerClass, loader, intfs); 13. 14. /获得与制定类装载器和一组接口相关的代理类类型对象 15. Class cl = getProxyClass0(loader, intfs); 16. try 17. 18. if (sm != null) 19. 20. checkNewProxyPermission(Reflection.getCalle

14、rClass(), cl); 21. 22. / 通过反射获取构造函数对象并生成代理类实例 23. final Constructor cons = cl.getConstructor(constructorParams); 24. final InvocationHandler ih = h; 25. if (!Modifier.isPublic(cl.getModifiers) 26. 27. AccessController.doPrivileged(new PrivilegedAction 28. 29. public Void run 30. 31. cons.setAccessib

15、le(true); 32. return null; 33. 34. ); 35. 36. return cons.newInstance(new Objecth); 37. 38. catch (IllegalAccessException|InstantiationException e) 39. 40. throw new InternalError(e.toString, e); 41. 42. catch (InvocationTargetException e) 43. 44. Throwable t = e.getCause; 45. if (t instanceof Runti

16、meException) 46. 47. throw (RuntimeException) t; 48. 49. else 50. 51. throw new InternalError(t.toString, t); 52. 53. 54. catch (NoSuchMethodException e) 55. 56. throw new InternalError(e.toString, e); 57. 58. 四、模拟实现Proxy类 根据上面的原理介绍,我们可以自己模拟实现Proxy类: 1. public class Proxy 2. 3. public static Object

17、newProxyInstance(Class inface,InvocationHandle h) throws Exception 4. 5. String rt=rn; 6. String methodStr=; 7. Method methods=inface.getMethods; 8. for(Method m:methods) 9. 10. methodStr+=Override+rt+ 11. public void +m.getName+rt+ + rt + 12. try +rt+ 13. Method md=+inface.getName+.class.getMethod(

18、+m.getName+);+rt+ 14. h.invoke(this,md);+rt+ 15. catch(Exception e)e.printStackTrace;+rt+ 16. 17. ; 18. 19. String src=package test;+rt+ 20. import java.lang.reflect.Method;+rt+ 21. public class ServiceImpl2 implements +inface.getName+ rt+ 22. +rt+ 23. public ServiceImpl2(InvocationHandle h)+rt+ 24.

19、 +rt+ 25. this.h = h;+rt+ 26. +rt+ 27. test.InvocationHandle h;+rt+ 28. methodStr+ 29. ; 30. String fileName=d:/src/test/ServiceImpl2.java; 31. /compile 32. compile(src, fileName); 33. /load into memory and create instance 34. Object m = loadMemory(h); 35. 36. return m; 37. 38. private static void c

20、ompile(String src, String fileName) throws IOException 39. 40. File f=new File(fileName); 41. FileWriter fileWriter=new FileWriter(f); 42. fileWriter.write(src); 43. fileWriter.flush; 44. fileWriter.close; 45. /获取此平台提供的Java编译器 46. JavaCompiler compiler=ToolProvider.getSystemJavaCompiler; 47. /获取一个标准

21、文件管理器实现的新实例 48. StandardJavaFileManager fileManager=compiler.getStandardFileManager(null,null, null); 49. /获取表示给定文件的文件对象 50. Iterable units=fileManager.getJavaFileObjects(fileName); 51. /使用给定组件和参数创建编译任务的 future 52. CompilationTask t=compiler.getTask(null, fileManager, null, null, null, units); 53. /

22、执行此编译任务 54. t.call; 55. fileManager.close; 56. 57. private static Object loadMemory(InvocationHandle h) 58. throws MalformedURLException, ClassNotFoundException, 59. NoSuchMethodException, InstantiationException, 60. IllegalAccessException, InvocationTargetException 61. 62. URL urls=new URL new URL(

23、file:/+d:/src/); 63. /从路径d:/src/加载类和资源 64. URLClassLoader ul=new URLClassLoader(urls); 65. Class c=ul.loadClass(test.ServiceImpl2); 66. /返回Class对象所表示的类的指定公共构造方法。 67. Constructor ctr=c.getConstructor(InvocationHandle.class); 68. /使用此 Constructor对象ctr表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例 69. Object

24、 m = ctr.newInstance(h); 70. return m; 71. 72. 五、总结 1、所谓的动态代理就是这样一种class,它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后改 class就宣称它实现了这些interface,但是其实它不会替你作实质性的工作,而是根据你在生成实例时提供的参数handler(即 InvocationHandler接口的实现类),由这个Handler来接管实际的工作。 2、Proxy的设计使得它只能支持interface的代理,Java的继承机制注定了动态代理类无法实现对class的动态代理,因为多继承在Java中本质上就行不通。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号