动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。相对于静态代理,它的优势是不需要事先知道被代理的类型,可以与被代理的类解耦,同时可以大大减少代理类的数量。
JDK动态代理的例子
Subject.java
1 package test.proxy;
2
3 public interface Subject {
4 int doSomething();
5 }
RealSubject.java
1 package test.proxy;
2
3 public class RealSubject implements Subject {
4 @Override
5 public int doSomething() {
6 System.out.println("RealSubject do something");
7 return 10;
8 }
9 }
ProxyHandler.java
1 package test.proxy;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5
6 public class ProxyHandler implements InvocationHandler {
7 private Object source;
8 public ProxyHandler(Object obj) {
9 this.source = obj;
10 }
11
12 @Override
13 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
14 System.out.println("Before");
15 Object r = method.invoke(this.source, args);
16 System.out.println("End");
17 return r;
18 }
19 }
调用类的实现:
1 package test.proxy;
2
3 import java.lang.reflect.Proxy;
4
5 public class TestProxy {
6 public static void main(String[] args) {
7 RealSubject realSubject = new RealSubject();
8 Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), new ProxyHandler(realSubject));
9 int result = subject.doSomething();
10 System.out.println(result);
11 }
12 }
输出结果:
1Before
2RealSubject do something
3End
410
5
6Process finished with exit code 0
通过加入如下属性System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);,可以将动态生成的代理类保存到磁盘,得到的动态代理类文件反编译得到如下:
1 //
2 // Source code recreated from a .class file by IntelliJ IDEA
3 // (powered by Fernflower decompiler)
4 //
5
6 package com.sun.proxy;
7
8 import java.lang.reflect.InvocationHandler;
9 import java.lang.reflect.Method;
10 import java.lang.reflect.Proxy;
11 import java.lang.reflect.UndeclaredThrowableException;
12 import test.proxy.Subject;
13
14 public final class $Proxy0 extends Proxy implements Subject {
15 private static Method m1;
16 private static Method m3;
17 private static Method m2;
18 private static Method m0;
19
20 public $Proxy0(InvocationHandler var1) throws {
21 super(var1);
22 }
23
24 public final boolean equals(Object var1) throws {
25 try {
26 return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
27 } catch (RuntimeException | Error var3) {
28 throw var3;
29 } catch (Throwable var4) {
30 throw new UndeclaredThrowableException(var4);
31 }
32 }
33
34 public final int doSomething() throws {
35 try {
36 return (Integer)super.h.invoke(this, m3, (Object[])null);
37 } catch (RuntimeException | Error var2) {
38 throw var2;
39 } catch (Throwable var3) {
40 throw new UndeclaredThrowableException(var3);
41 }
42 }
43
44 public final String toString() throws {
45 try {
46 return (String)super.h.invoke(this, m2, (Object[])null);
47 } catch (RuntimeException | Error var2) {
48 throw var2;
49 } catch (Throwable var3) {
50 throw new UndeclaredThrowableException(var3);
51 }
52 }
53
54 public final int hashCode() throws {
55 try {
56 return (Integer)super.h.invoke(this, m0, (Object[])null);
57 } catch (RuntimeException | Error var2) {
58 throw var2;
59 } catch (Throwable var3) {
60 throw new UndeclaredThrowableException(var3);
61 }
62 }
63
64 static {
65 try {
66 m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
67 m3 = Class.forName("test.proxy.Subject").getMethod("doSomething");
68 m2 = Class.forName("java.lang.Object").getMethod("toString");
69 m0 = Class.forName("java.lang.Object").getMethod("hashCode");
70 } catch (NoSuchMethodException var2) {
71 throw new NoSuchMethodError(var2.getMessage());
72 } catch (ClassNotFoundException var3) {
73 throw new NoClassDefFoundError(var3.getMessage());
74 }
75 }
76 }