java 动态代理分析

为什么要使用代理。

先看一个简单的使用案例

 1 import java.lang.reflect.Proxy;
 2 
 3 public class ProxyTest {
 4 
 5     public static void main(String[] args) {
 6      //开启保存代理类
 7         System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
 8      
 9         Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class[]{ProxyDemo.class}, new InvocationHandlerDemo());
10 
11     }
12 }
Proxy.newProxyInstance方法传入三个参数,类加载器,需要被代理的接口,代理类处理接口。结果返回的是Object对象。
jdk版本1.7,源码如下:
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        if (h == null) {
            throw new NullPointerException();
        }
     //检查权限
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
        }

        //生成代理类,核心是这个方法
        Class<?> cl = getProxyClass0(loader, interfaces);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
       //获取构造器
final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() {
              //创建对象
return newInstance(cons, ih); } }); } else {
          //创建对象
return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

     //首先从缓存中获取代理类,如果没有,通过Proxy.ProxyClassFactory类生成代理类并放入缓存,然后返回代理类。 return proxyClassCache.get(loader, interfaces); }

下面分析 Proxy.ProxyClassFactory 类的apply方法:

 1 @Override
 2         public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
 3 
 4             Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
 5             for (Class<?> intf : interfaces) {
 6                 /*
 7                  * 验证代理接口
 8                  * 
 9                  */
10                 Class<?> interfaceClass = null;
11                 try {
12                     interfaceClass = Class.forName(intf.getName(), false, loader);
13                 } catch (ClassNotFoundException e) {
14                 }
15                 if (interfaceClass != intf) {
16                     throw new IllegalArgumentException(
17                         intf + " is not visible from class loader");
18                 }
19                 /*
20                  * 验证是否是接口
21                  * 
22                  */
23                 if (!interfaceClass.isInterface()) {
24                     throw new IllegalArgumentException(
25                         interfaceClass.getName() + " is not an interface");
26                 }
27                 /*
28                  * 验证接口是否有多个
29                  */
30                 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
31                     throw new IllegalArgumentException(
32                         "repeated interface: " + interfaceClass.getName());
33                 }
34             }
35 
36             String proxyPkg = null;     // package to define proxy class in
37 
38             /*
39              *  
40              *  验证同一包下非公共接口,包名是否一致
41              *  
42              */
43             for (Class<?> intf : interfaces) {
44                 int flags = intf.getModifiers();
45                 if (!Modifier.isPublic(flags)) {
46                     String name = intf.getName();
47                     int n = name.lastIndexOf('.');
48                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
49                     if (proxyPkg == null) {
50                         proxyPkg = pkg;
51                     } else if (!pkg.equals(proxyPkg)) {
52                         throw new IllegalArgumentException(
53                             "non-public interfaces from different packages");
54                     }
55                 }
56             }
57 
58             if (proxyPkg == null) {
59                 // 如果是pulic接口,采用默认包名
60                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
61             }
62 
63             /*
64              * 组装代理类名
65              */
66             long num = nextUniqueNumber.getAndIncrement();
67             String proxyName = proxyPkg + proxyClassNamePrefix + num;
68 
69             /*
70              * 生成代理类,核心方法是ProxyGenerator 中的 generateClassFile方法。
71              */
72             byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
73                 proxyName, interfaces);
74             try {
75                 return defineClass0(loader, proxyName,
76                                     proxyClassFile, 0, proxyClassFile.length);
77             } catch (ClassFormatError e) {
78                 /*
79                  * A ClassFormatError here means that (barring bugs in the
80                  * proxy class generation code) there was some other
81                  * invalid aspect of the arguments supplied to the proxy
82                  * class creation (such as virtual machine limitations
83                  * exceeded).
84                  */
85                 throw new IllegalArgumentException(e.toString());
86             }
87         }

 private byte[] generateClassFile() {
     //添加hashCode、equals、toString方法,到代理方法集合中
this.addProxyMethod(hashCodeMethod, Object.class); this.addProxyMethod(equalsMethod, Object.class); this.addProxyMethod(toStringMethod, Object.class); int var1; int var3;
     //遍历代理接口,将接口中的方法添加到代理方法集合中
for(var1 = 0; var1 < this.interfaces.length; ++var1) { Method[] var2 = this.interfaces[var1].getMethods(); for(var3 = 0; var3 < var2.length; ++var3) { this.addProxyMethod(var2[var3], this.interfaces[var1]); } } Iterator var7 = this.proxyMethods.values().iterator();      //验证代理方法集合中返回类型 List var8; while(var7.hasNext()) { var8 = (List)var7.next(); checkReturnTypes(var8); } Iterator var11; try {
       //生成含有InvoicationHandler参数的构造方法,并添加到方法集合中
this.methods.add(this.generateConstructor()); var7 = this.proxyMethods.values().iterator();        //遍历代理方法集合,生成方法,字段,放入到方法集合,字段集合中 while(var7.hasNext()) { var8 = (List)var7.next(); var11 = var8.iterator(); while(var11.hasNext()) { ProxyGenerator.ProxyMethod var4 = (ProxyGenerator.ProxyMethod)var11.next(); this.fields.add(new ProxyGenerator.FieldInfo(var4.methodFieldName, "Ljava/lang/reflect/Method;", 10)); this.methods.add(var4.generateMethod()); } }        //生成类构造器,添加到方法中 this.methods.add(this.generateStaticInitializer()); } catch (IOException var6) { throw new InternalError("unexpected I/O Exception"); } if (this.methods.size() > 65535) { throw new IllegalArgumentException("method limit exceeded"); } else if (this.fields.size() > 65535) { throw new IllegalArgumentException("field limit exceeded"); } else { this.cp.getClass(dotToSlash(this.className)); this.cp.getClass("java/lang/reflect/Proxy"); for(var1 = 0; var1 < this.interfaces.length; ++var1) { this.cp.getClass(dotToSlash(this.interfaces[var1].getName())); } this.cp.setReadOnly();
       //构造字节输出流,按照class文件格式,顺序输出到字节数组中 ByteArrayOutputStream var9
= new ByteArrayOutputStream(); DataOutputStream var10 = new DataOutputStream(var9); try {
          //写入魔数 var10.writeInt(
-889275714);
          //写入此版本号 var10.writeShort(
0);
          //写入主版本号 var10.writeShort(
49);
          //写入常量池
this.cp.write(var10);
          //写入访问修饰符 var10.writeShort(
49);
          //写入类索引 var10.writeShort(
this.cp.getClass(dotToSlash(this.className)));
          //写入父类索引 var10.writeShort(
this.cp.getClass("java/lang/reflect/Proxy"));
          //写入接口数量 var10.writeShort(
this.interfaces.length);           //写入接口 for(var3 = 0; var3 < this.interfaces.length; ++var3) { var10.writeShort(this.cp.getClass(dotToSlash(this.interfaces[var3].getName()))); }           //写入字段计数 var10.writeShort(this.fields.size()); var11 = this.fields.iterator();           //写入字段 while(var11.hasNext()) { ProxyGenerator.FieldInfo var12 = (ProxyGenerator.FieldInfo)var11.next(); var12.write(var10); }            //写入方法计数 var10.writeShort(this.methods.size()); var11 = this.methods.iterator();           //写入方法 while(var11.hasNext()) { ProxyGenerator.MethodInfo var13 = (ProxyGenerator.MethodInfo)var11.next(); var13.write(var10); }           //写入属性计数 var10.writeShort(0); return var9.toByteArray(); } catch (IOException var5) { throw new InternalError("unexpected I/O Exception"); } } }

从上面源码,可以看出生成的代理类应该包括代理接口中所有方法,Object的hashcode,equals,toString方法,一个含有InvocationHandler参数的实例构造方法,一个类初始方法。下面让我们看下生成的代理类源码:

 1 public final class $Proxy0 extends Proxy implements ProxyDemo {
 2     private static Method m1;
 3     private static Method m3;
 4     private static Method m0;
 5     private static Method m2;
 6 
 7     public $Proxy0(InvocationHandler var1) throws  {
 8         super(var1);
 9     }
10 
11     public final boolean equals(Object var1) throws  {
12         try {
13             return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
14         } catch (RuntimeException | Error var3) {
15             throw var3;
16         } catch (Throwable var4) {
17             throw new UndeclaredThrowableException(var4);
18         }
19     }
20 
21     public final void sayHello(String var1) throws  {
22         try {
23             super.h.invoke(this, m3, new Object[]{var1});
24         } catch (RuntimeException | Error var3) {
25             throw var3;
26         } catch (Throwable var4) {
27             throw new UndeclaredThrowableException(var4);
28         }
29     }
30 
31     public final int hashCode() throws  {
32         try {
33             return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
34         } catch (RuntimeException | Error var2) {
35             throw var2;
36         } catch (Throwable var3) {
37             throw new UndeclaredThrowableException(var3);
38         }
39     }
40 
41     public final String toString() throws  {
42         try {
43             return (String)super.h.invoke(this, m2, (Object[])null);
44         } catch (RuntimeException | Error var2) {
45             throw var2;
46         } catch (Throwable var3) {
47             throw new UndeclaredThrowableException(var3);
48         }
49     }
50 
51     static {
52         try {
53             m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
54             m3 = Class.forName("com.yishi.invoice.proxy.ProxyDemo").getMethod("sayHello", Class.forName("java.lang.String"));
55             m0 = Class.forName("java.lang.Object").getMethod("hashCode");
56             m2 = Class.forName("java.lang.Object").getMethod("toString");
57         } catch (NoSuchMethodException var2) {
58             throw new NoSuchMethodError(var2.getMessage());
59         } catch (ClassNotFoundException var3) {
60             throw new NoClassDefFoundError(var3.getMessage());
61         }
62     }
63 }
View Code

我们可以看到,调用代理类的sayHello方法,实际上调用的是InvocationHandler.invoke方法。

需要注意:代理类中通过反射获取到代理接口的Method对象,并传入到InvocationHandler.invoke方法中。也就是说invoke方法中需要通过Method发射来调用被代理类的方法。

下面看一个复杂的例子:

包结构如下:

  1 import java.io.File;
  2 import java.io.IOException;
  3 import java.lang.reflect.Modifier;
  4 import java.net.URL;
  5 import java.util.*;
  6 
  7 public class DaoContainer {
  8 
  9     /**
 10      * 存储代理类
 11      * key为接口名称
 12      * value为代理类
 13      */
 14     private static Map<String, Object> daoMap = new HashMap<String, Object>();
 15 
 16     /**
 17      * 接口class对象
 18      */
 19     private static List<Class<?>> interfaces = new ArrayList<Class<?>>();
 20 
 21     /**
 22      * 存储实例对象
 23      * key 为 接口class对象
 24      * value为 实例对象
 25      */
 26     private static Map<Class<?>, List<Object>> maps = new HashMap<Class<?>, List<Object>>();
 27 
 28     /**
 29      * 解析包下的接口
 30      * @param pkgBase
 31      */
 32     public void parseInterface(String pkgBase) {
 33         //解析包路径
 34         //此处简单处理,支持单路劲
 35         String[] p = splitPkg(pkgBase);
 36         for (String str:p) {
 37             Enumeration<URL> resources = null;
 38             try {
 39                 resources = DaoContainer.class.getClassLoader().getResources(str);
 40                 while (resources.hasMoreElements()){
 41                     URL url = resources.nextElement();
 42                     File rootFile = new File(url.getFile());
 43                     if (rootFile.exists()) {
 44                         if (rootFile.isDirectory()) {
 45                             File[] subFiles = rootFile.listFiles();
 46                             for (File f : subFiles) {
 47                                 String interfaceName = pkgBase+ "." + f.getName().substring(0,f.getName().lastIndexOf("."));
 48                                 System.out.println(interfaceName);
 49                                 try {
 50                                     /**
 51                                      * 可以通过解析class文件,获取类属性,减少不必要的类加载。然后通过判断哪些类是需要加载的
 52                                      * 此处简单处理
 53                                      */
 54                                     Class<?> cl = Class.forName(interfaceName,false, DaoContainer.class.getClassLoader());
 55                                     if (Modifier.isInterface(cl.getModifiers())) {
 56                                         interfaces.add(cl);
 57                                     } else if (!Modifier.isInterface(cl.getModifiers()) && !Modifier.isAbstract(cl.getModifiers()) && Modifier.isPublic(cl.getModifiers())) {
 58                                         //如果不是接口,分析父类接口
 59                                         Class<?>[] inter = cl.getInterfaces();
 60                                         for (Class i : inter ) {
 61                                             if (Modifier.isPublic(i.getModifiers())) {
 62                                                 List<Object> objs = maps.get(i);
 63                                                 if (objs == null) {
 64                                                     objs = new ArrayList<Object>();
 65                                                     maps.put(i, objs);
 66                                                 }
 67                                                 objs.add(cl.newInstance());
 68                                             }
 69                                         }
 70                                     }
 71                                 } catch (ClassNotFoundException e) {
 72                                     e.printStackTrace();
 73                                 } catch (IllegalAccessException e) {
 74                                     e.printStackTrace();
 75                                 } catch (InstantiationException e) {
 76                                     e.printStackTrace();
 77                                 }
 78                             }
 79                         }
 80                     }
 81                 }
 82             } catch (IOException e) {
 83                 e.printStackTrace();
 84             }
 85         }
 86     }
 87 
 88     /**
 89      * 以 ,或者; 作为分隔符
 90      * @param pkgBase
 91      * @return
 92      */
 93     private String[] splitPkg(String pkgBase) {
 94         //简单处理
 95         pkgBase = pkgBase.replace(".","/");
 96         return new String[]{pkgBase};
 97     }
 98 
 99     /**
100      * 创建代理类
101      */
102     private void createProxy() {
103         for (Class<?> cl : interfaces) {
104             //创建代理类
105             Object proxy = DaoProxyFactory.proxyInstance(cl);
106 
107             daoMap.put(cl.getName(),proxy);
108         }
109 
110         Set<Map.Entry<Class<?>, List<Object>>> keys = maps.entrySet();
111         Iterator<Map.Entry<Class<?>, List<Object>>> iterator = keys.iterator();
112 
113         while (iterator.hasNext()) {
114             Map.Entry<Class<?>, List<Object>> entry = iterator.next();
115 
116             Class<?> key = entry.getKey();
117 
118             List<Object> objs = entry.getValue();
119 
120             for (int i = 0; null != objs && i < objs.size(); i++) {
121                 Object o = objs.get(i);
122                 Object obj = DaoProxyFactory.proxyInstance(key, o);
123                 daoMap.put(o.getClass().getName(), obj);
124             }
125         }
126 
127     }
128 
129     /**
130      * 搜索包下接口
131      * @param pkgBase
132      */
133     public void searchPkgBean(String pkgBase) {
134         parseInterface(pkgBase);
135         createProxy();
136     }
137 
138     /**
139      * 通过key获取代理类
140      * @return
141      */
142     public Object getProxyObjectByKey(String key) {
143         return daoMap.get(key);
144     }
145 
146 }
View Code
 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 import java.lang.reflect.Proxy;
 4 
 5 public class DaoProxyFactory {
 6 
 7     private static CommonSolvDemo commonSolvDemo = new CommonSolvDemo();
 8 
 9     public DaoProxyFactory() {
10     }
11 
12     public DaoProxyFactory(CommonSolvDemo com) {
13         this.commonSolvDemo = com;
14     }
15 
16     //代理接口
17     public static Object proxyInstance(Class<?> inter) {
18         Object obj = null;
19         try {
20             obj = Proxy.newProxyInstance(DaoProxyFactory.class.getClassLoader(), new Class[]{inter}, new DaoInvocationHandler());
21         } catch (Exception e) {
22             e.printStackTrace();
23         }
24         return obj;
25     }
26 
27     //代理实现共同接口的实例
28     public static Object proxyInstance(Class<?> inter, Object obj) {
29         Object res = null;
30         try {
31             res =  Proxy.newProxyInstance(DaoProxyFactory.class.getClassLoader(), new Class[]{inter}, new DaoInvocationHandler1(obj));
32         } catch (Exception e) {
33             e.printStackTrace();
34         }
35         return res;
36     }
37 
38     private static class DaoInvocationHandler implements InvocationHandler {
39 
40         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
41 
42             commonSolvDemo.commonSolvStart();
43 
44             commonSolvDemo.commonSolvEnd();
45 
46             return null;
47         }
48     }
49 
50     private static class DaoInvocationHandler1 implements InvocationHandler {
51 
52         private Object target;
53 
54         public DaoInvocationHandler1(Object target) {
55             this.target = target;
56         }
57 
58         public DaoInvocationHandler1() {
59         }
60 
61         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
62             commonSolvDemo.commonSolvStart();
63             method.invoke(target,args);
64             commonSolvDemo.commonSolvEnd();
65             return null;
66         }
67     }
68 }
View Code
 1 public class CommonSolvDemo {
 2 
 3 
 4     public void commonSolvStart() {
 5         System.out.println("公共处理开始");
 6     }
 7 
 8 
 9     public void commonSolvEnd() {
10         System.out.println("公共处理结束");
11     }
12 
13 }
View Code
 1 import java.lang.reflect.Proxy;
 2 
 3 public class ProxyTest {
 4 
 5     public static void main(String[] args) {
 6 //        test1();
 7         test2();
 8     }
 9 
10     public static void test2() {
11         DaoContainer container = new DaoContainer();
12         container.searchPkgBean("com.yishi.invoice.proxy");
13 //        //这种情况类似mybatis底层的代理生成方式
14         ProxyDemo p = (ProxyDemo) container.getProxyObjectByKey("com.yishi.invoice.proxy.ProxyDemo");
15         p.sayHello("haha");
16 
17         //代理实现统一接口的实例,类似spring底层代理的一种
18         SqlSession sql = (SqlSession) container.getProxyObjectByKey("com.yishi.invoice.proxy.SqlSessionTemplete");
19         sql.selectLIst("312","21");
20     }
21 
22     public static void test1() {
23         System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
24 
25         Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class[]{ProxyDemo.class}, new InvocationHandlerDemo());
26     }
27 
28 }

总结下,动态代理底层是字节码层面的技术,利用反射获取到需要代理接口方法,然后根据class字节码标准,生成二进制数据。

回到最开始的问题,为什么要使用代理?当需要对一些类,接口提供统一功能的时候,可以考虑使用代理模式。静态代理采用硬编码的方式实现,其思想本质上是一样的。

spring采用两种代理,cglib与jdk代理。如果是接口的话,采用jdk方式,如果是非接口,采用cglib方式。

后面将分析cglib代理原理,敬请期待。

原文地址:https://www.cnblogs.com/hf-china/p/9451003.html