时间:2021-05-19
一、概述
代理是一种设计模式,其目的是为其他对象提供一个代理以控制对某个对象的访问,代理类负责为委托类预处理消息,过滤消息并转发消息以及进行消息被委托类执行后的后续处理。为了保持行为的一致性,代理类和委托类通常会实现相同的接口。
按照代理的创建时期,代理类可分为两种:
静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,也就是说在程序运行前代理类的.class文件就已经存在。
动态代理:在程序运行时运用反射机制动态创建生成。
下面在将动态代理的实现机制之前先简单介绍一下静态代理。
二、静态代理
上面说过,代理类和委托类一般都要实现相同的接口,下面先定义这个接口:
委托类作为接口的一种实现,定义如下:
public class ServiceImpl implements Service{ public void add() { System.out.println("添加用户!"); }}假如我们要对委托类加一些日志的操作,代理类可做如下定义:
public class ServiceProxy implements Service{ private Service service; public ServiceProxy(Service service) { super(); this.service = service; } public void add() { System.out.println("服务开始"); service.add(); System.out.println("服务结束"); }}编写测试类:
public class TestMain{ public static void main(String[] args) { Service serviceImpl=new ServiceImpl(); Service proxy=new ServiceProxy(serviceImpl); proxy.add(); }}运行测试程序,结果如下图:
从上面的代码可以看到,静态代理类只能为特定的接口服务,如果要服务多类型的对象,就要为每一种对象进行代理。我们就会想是否可以通过一个代理类完成全部的代理功能,于是引入的动态代理的概念。
三、动态代理
Java的动态代理主要涉及两个类,Proxy和InvocationHandler。
Proxy:提供了一组静态方法来为一组接口动态地生成代理类及其对象。
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器static InvocationHandler getInvocationHandler(Object proxy)// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象static Class getProxyClass(ClassLoader loader, Class[] interfaces)// 方法 3:该方法用于判断指定类对象是否是一个动态代理类static boolean isProxyClass(Class cl)// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)InvocationHandler:它是调用处理器接口,自定义了一个invok方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问
// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行Object invoke(Object proxy, Method method, Object[] args)实现Java的动态代理,具体有以下四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器
2、通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类
3、通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器类接口类型
4、通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入
下面根据上述的四个步骤来实现自己的动态代理的示例:
接口和接口的实现类(即委托类)跟上面静态代理的代码一样,这里我们来实现InvocationHandler接口创建自己的调用处理器
public class ServiceHandle implements InvocationHandler{ private Object s; public ServiceHandle(Object s) { this.s = s; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("服务开始"); //invoke表示对带有指定参数的指定对象调用由此 Method 对象表示的底层方法 Object result=method.invoke(s, args); System.out.println("服务结束"); return result; }}编写测试类:
public class TestMain{ public static void main(String[] args) { Service service=new ServiceImpl(); InvocationHandler handler=new ServiceHandle(service); Service s=(Service) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), handler); s.add(); }}运行测试程序,结果同静态代理。我们可以看到上述代码并没有我们之前说的步骤2和3,这是因为Prox的静态方法newProxyInstance已经为我们封装了这两个步骤。具体的内部实现如下:
// 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... });// 通过反射从生成的类对象获得构造函数对象Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });// 通过构造函数对象创建动态代理类实例Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });newProxyInstance函数的内部实现为:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException { //检查h不为空,否则抛异常 Objects.requireNonNull(h); //获得与制定类装载器和一组接口相关的代理类类型对象 final Class<?>[] intfs = interfaces.clone(); //检查接口类对象是否对类装载器可见并且与类装载器所能识别的接口类对象是完全相同的 final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //获得与制定类装载器和一组接口相关的代理类类型对象 Class<?> cl = getProxyClass0(loader, intfs); try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } // 通过反射获取构造函数对象并生成代理类实例 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }四、模拟实现Proxy类
根据上面的原理介绍,我们可以自己模拟实现Proxy类:
五、总结
1、所谓的动态代理就是这样一种class,它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后改class就宣称它实现了这些interface,但是其实它不会替你作实质性的工作,而是根据你在生成实例时提供的参数handler(即InvocationHandler接口的实现类),由这个Handler来接管实际的工作。
2、Proxy的设计使得它只能支持interface的代理,Java的继承机制注定了动态代理类无法实现对class的动态代理,因为多继承在Java中本质上就行不通。
以上就是本文的全部内容,希望对大家的学习有所帮助。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
Java反射机制与动态代理,使得Java更加强大,Spring核心概念IoC、AOP就是通过反射机制与动态代理实现的。1Java反射示例:Useruser=ne
java代理有jdk动态代理、cglib代理,这里只说下jdk动态代理,jdk动态代理主要使用的是java反射机制(既java.lang.reflect包)原理
详解javaJDK动态代理类分析(java.lang.reflect.Proxy)/***JDK动态代理类分析(java.lang.reflect.Proxy使
Java语言中反射动态代理接口的解释与演示Java在JDK1.3的时候引入了动态代理机制、可以运用在框架编程与平台编程时候捕获事件、审核数据、日志等功能实现,首
详解Java动态代理的实现及应用Java动态代理其实写日常业务代码是不常用的,但在框架层一起RPC框架的客户端是非常常见及重要的。spring的核心思想aop的