时间:2021-05-20
代理模式:为其他对象提供一种代理以控制某个对象的访问。用在:在某些情况下,一个客户不想或者不能直接访问另一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用,代理对象还可以完成它附加的操作。
例子:就像房东、租客、中介的关系。中介(代理对象)为房东(真实对象)出租房子,租客(客户)通过中介(代理对象)来找房子租房子,中介完成了租房以后可以收取中介费(附加操作)。
先看看静态代理模式,通过上面对代理模式的理解,可以了解到代理模式:即不直接通过new一个真实对象来调用方法,而是通过代理对象来调用一个方法,所以代理对象包含真实对象的引用。下面看一下代码
接口:Subject包含一个方法
package com.example.designpattern.proxy; public interface Subject { void request(); }RealSubject类,实现了Subject接口,为了简单起见,方法简单的输出一句话:
package com.example.designpattern.proxy;public class RealSubject implements Subject {//真是角色实现了public void request() {System.out.println("From real subject");}}代理类ProxySubject,也要实现Subject接口,实现Subject里面的方法,但是在这里里面是通过调用真实对象来实现的。
package com.example.designpattern.proxy;public class ProxySubject implements Subject {private RealSubject realSubject; //代理角色内部引用了真实角色//代理角色实现目标动作public void request() {this.preRequest(); //在真实角色操作之前所附加的操作if (realSubject == null){realSubject = new RealSubject();}realSubject.request(); // 真实角色所完成的事情this.afterRequet(); //在真实角色操作之后附加的操作}//代理角色之前完成的动作private void preRequest(){System.out.println("pre request");}//代理角色之后完成的动作private void afterRequet(){System.out.println("after request");}}客户调用者
package com.example.designpattern.proxy;public class Client {public static void main(String[] args) {ProxySubject proxy = new ProxySubject();//通过代理对象来调用方法proxy.request(); }}静态代理:
可以运行一下这些代码哦, 可以在Client类中看到,是通过代理ProxySubject的对象proxy来调用方法的,在代理类ProxySubject中,有一个真实对象的引用,在代理对象的中request()方法调用了真实对象的方法。这样的模式叫做代理模式。
优点是:
1. 代理模式能将代理对象与真实对象被调用的目标对象分离。
2. 一定程度上降低了系统的耦合度,扩展性好。
代理类中包含了对真实主题的引用,这样做也有缺点:
1. 真实对象与代理类一一对应,增加真实类也要增加代理类,这样做会快速的增加类的数量,使得系统变得复杂。
2. 设计代理以前真实主题必须事先存在,不太灵活。
采用动态代理可以解决以上问题,动态代理是相对于静态代理来说的。
可能你也会说怎么样实现动态创建实例,以前我们创建实例不都是通过new 的方式来实现的吗?
Hello hi = new Hello();
那么动态创建实例是由Java提供的功能,就不需要我们去new 对象,他已经定义好了静态方法Proxy.newProxyInstance(),只要传入参数调用就可以。Java文档里面有哦,如图:
Java标准库提供了一种动态代理(DynamicProxy)的机制:可以在运行期动态创建某个interface的实例。
参数解释:
Proxy.newProxyInstance( ClassLoader loader, // 传入ClassLoader Class<?>[] interfaces, // 传入要调用的接口的方法数组 InvocationHandler h); //传入InvocationHandler 的实例下面看一下动态代理例子代码:
Subject 接口
package design.dynamicproxy;public interface Subject {void request(String str);}RealSubject类 实现 Subject 接口
package design.dynamicproxy;public class RealSubject implements Subject {@Overridepublic void request(String str) {System.out.println("From Real Subject!" + " args:" + str );}}动态代理类DynamicSubject 实现了InvocationHandler,重写invoke()方法
package design.dynamicproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/*** 该代理类的内部属性时Object类型,实际使用时,使用该类的构造方法传递一个对象* 此外该类还实现了invoke() 方法,该方法中的method.invoke() 其实就是要调用被代理对象的要执行的方法* 方法参数是object,表示该方法从属于object对象,通过动态代理类,我们可以在执行真是对象的* 方法前后可以加入一些额外的方法*/public class DynamicSubject implements InvocationHandler {//引入的类型是Object的,可以随便传入任何一个对象private Object object;public DynamicSubject(Object object){this.object = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before calling:" + method);//等价于realSubject的request() 方法,如果这里不调用的话,不会调用Method 对象中的方法method.invoke(object, args);System.out.println("after calling:" + method);return null;}}Client类
package design.dynamicproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class Client { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); InvocationHandler handler = new DynamicSubject(realSubject); Class<?> classType = handler.getClass(); //下面的代码一次性生成代理 // 动态生成了class com.sun.proxy.$Proxy0 的实例, Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),handler); subject.request("eather"); System.out.println(subject.getClass()); //输出class com.sun.proxy.$Proxy0,可以看到Proxy.newProxyInstance() 是系统自动生成的实例 }}在Client中可以看到,我们这里调用方法的是 subject.request("eather"); 这个对象subject 不是通过new DynamicSubject()生成的,而是Java内部写好的方法在运行时动态生成对象;可能有人说
InvocationHandler handler = new DynamicSubject(realSubject);
这里不是通过new new DynamicSubject(realSubject); 生成了一个对象吗? 是的,但是它是InvocationHandler 类型的,主要是传递一个InvocationHandler类型参数给Proxy.newProxyInstance(); 即最后一个参数。通过Client类的最后一句输出可以看到它是 class com.sun.proxy.$Proxy0 ,这是Java运行时生成的。
解决了静态代理的难题:1. 真实对象与代理类一一对应,增加真实类也要增加代理类,这样做会快速的增加类的数量,使得系统变得复杂。 为什么这么说呢, 因为代理类引用的类型是Object的,可以随便传入任何一个对象,当真实类增加时,代理类不用增加,new DynamicSubject(object); new的时候把要传入的对象传进去即可。
下面是Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h); 这个方法的源码啦,可以看看,深入了解一下
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{ Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /** Look up or generate the designated proxy class.生成一个代理类对象*/ Class<?> cl = getProxyClass0(loader, intfs); /** Invoke its constructor with the designated invocation handler.使用指定的调用处理程序调用其构造函数。就是使用InvocationHandler 实例调用【要调用方法的那个类】的构造方法*/ 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); }}以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文实例讲述了Java动态代理实现方法。分享给大家供大家参考,具体如下:静态代理了解的差不多了,但是对于动态代理理解的还不是很通透,这里先把一些常用的动态代理实
今天来看看Java的另一种代理方式——JDK动态代理 我们之前所介绍的代理方式叫静态代理,也就是静态的生成代理对象,而动态代理则是在运行时创建代理对象。动
正文关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。静态代理1、
详解javaJDK动态代理类分析(java.lang.reflect.Proxy)/***JDK动态代理类分析(java.lang.reflect.Proxy使
java代理有jdk动态代理、cglib代理,这里只说下jdk动态代理,jdk动态代理主要使用的是java反射机制(既java.lang.reflect包)原理