一、代理模式简介以及静态代理动态代理区别
1. 关系图
静态代理:可以看出有一接口Sourceable,两个实现类Source,Proxy,Client调用的Proxy。理解一下就是Client通过Proxy来调用这个method,而不是直接通过Source来调用。
这就像我们的电脑开代理的时候,通过代理上网,而不是直连网络。
从这张类图中也可以看出实现代理模式的两个要点:
① 代理类和被代理类必须要实现同一接口 (看下面代码好理解,就是为了面向接口编程)
② 代理类的核心是做功能的增强,真正的method还是被代理类提供
(不好意思,下面这段代码体现的是装饰模式,知道真相的我眼泪掉下来,留着不改了,做个纪念)
装饰模式和代理模式的区别:代理模式在Proxy类中即需要new出被代理类,而装饰模式即是下面这样的在外面传入。
public class ProxyDemo {
public static void main(String args[]){ RealSubject subject = new RealSubject(); Proxy p = new Proxy(subject); p.request(); } } interface Subject{ void request(); } class RealSubject implements Subject{ public void request(){ System.out.println("request"); } }
// 面向接口在这里有体现,subject class Proxy implements Subject{ private Subject subject; public Proxy(Subject subject){ this.subject = subject;
// 真正的代理模式会这样写,两种模式的区别自己体会。
//this.subject = new RealSubject;
//这样写之后在main函数中只要new Proxy()就好了 } public void request(){ System.out.println("PreProcess"); subject.request(); System.out.println("PostProcess"); } }
2. 动态代理和静态代理区别
- 静态代理:代理类是在编译时就实现好的。也就是说 Java 编译完成后代理类是一个实际的 class 文件。
- 动态代理:代理类是在运行时生成的。也就是说 Java 编译完之后并没有实际的 class 文件,而是在运行时动态生成字节码,并加载到JVM中。
动态代理生成代理类类名以及字节码过程:
/* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); }
二、动态代理的实现以及实现原理
1. 声明共同接口
public interface Subject { void dating(); void sing(); }
2. 设置被代理类,也叫委托类
public class WeiTuoLei implements Subject{ @Override public void dating() { System.out.println("Time0"); } @Override public void sing() { System.out.println("Sing a Song"); } } class WeiTuoLei1 implements Subject{ @Override public void dating() { System.out.println("Time1"); } @Override public void sing() { System.out.println("Dance"); } }
3. 设置代理类的调用处理器(需实现InvocationHandler接口)
class ProxyHandler implements InvocationHandler{ // 真正被代理的对象也叫做委托对象 Subject subject; public ProxyHandler(Subject subject){ this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { dosomethingbefore(); Object invoke = method.invoke(subject, args); dosomethingafter(); return invoke; } private void dosomethingbefore() { System.out.println("==========before======="); } private void dosomethingafter() { System.out.println("==========after======="); } }
4. 测试
public class Main { public static void main(String[] args) { WeiTuoLei realSubject = new WeiTuoLei(); //1.创建委托对象 ProxyHandler handler = new ProxyHandler(realSubject); //2.创建调用处理器对象 //3.动态生成代理对象 Subject o = (Subject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);
//JDK内部就是通过这个方法生成的代理对象,我把它拿出来,咱们就可以看到动态生成了一个什么样的代理对象。 ProxyUtils.generateClassFile(WeiTuoLei.class,o.getClass().getName()); /** * Proxy.newProxyInstance等于如下动作 * //1. 根据类加载器和接口创建代理类 Class clazz = Proxy.getProxyClass(loader, interfaces); //2. 获得代理类的带参数的构造函数 Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); //3. 创建代理对象,并制定调用处理器实例为参数传入 Interface Proxy = (Interface)constructor.newInstance(new Object[] {handler}); */ //4.通过代理对象调用方法 o.sing(); } }
我的ProxyUtils(可以通过这个工具类看到动态生成的代理对象,其实就是把字节码保存了一下)
public class ProxyUtils { public static void generateClassFile(Class clazz, String proxyName) { byte[] proxyClassFile = ProxyGenerator.generateProxyClass( clazz.getName(), new Class[]{clazz}); String path = clazz.getResource(".").getPath() + proxyName + ".class"; File file = new File(path); try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } System.out.println(path); FileOutputStream out = null; try { out = new FileOutputStream(path); out.write(proxyClassFile); out.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } }
好,接下来我们来解剖一下它生成的这个代理类(字节码文件),用反编译工具看一下具体内容。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class WeiTuoLei extends Proxy implements WeiTuoLei { private static Method m1; private static Method m3; private static Method m9; private static Method m2; private static Method m4; private static Method m7; private static Method m6; private static Method m8; private static Method m10; private static Method m0; private static Method m5; public WeiTuoLei(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void dating() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void notify() throws { try { super.h.invoke(this, m9, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void sing() throws { try { super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void wait(long var1) throws InterruptedException { try { super.h.invoke(this, m7, new Object[]{var1}); } catch (RuntimeException | InterruptedException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); } } public final void wait(long var1, int var3) throws InterruptedException { try { super.h.invoke(this, m6, new Object[]{var1, var3}); } catch (RuntimeException | InterruptedException | Error var5) { throw var5; } catch (Throwable var6) { throw new UndeclaredThrowableException(var6); } } public final Class getClass() throws { try { return (Class)super.h.invoke(this, m8, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void notifyAll() throws { try { super.h.invoke(this, m10, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void wait() throws InterruptedException { try { super.h.invoke(this, m5, (Object[])null); } catch (RuntimeException | InterruptedException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("dating"); m9 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("notify"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m4 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("sing"); m7 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("wait", Long.TYPE); m6 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("wait", Long.TYPE, Integer.TYPE); m8 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("getClass"); m10 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("notifyAll"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); m5 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("wait"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
看着代码很多,实际上就是把一个类里的各个方法通过反射拿了出来,我这里看不到代理类的两个方法,因为我没法传参,但是大致思想就是这样。需要注意的是各个方法里写的都是super.h.invoke,那么这个super.h就是继承了invocationHandler的那个类(被代理类)。具体invoke的调用时机,可以看下面这边博客: