java之动态代理

摘要

相比于静态代理,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定一组接口及目标类对象就能动态的获得代理对象。

这里说的静态代理可以理解为之前使用的 装饰者模式,从之前使用装饰者模式实现 自己实现一个数据库连接池就可以明显可以看出它的缺点,如果接口有很多方法,而我们仅要装饰使用其中部分方法,我们还是不可避免的要实现它的其它方法。而动态代理就可以帮我们更细粒度的仅对我们要使用的方法进行增强。

JDK动态代理

使用

1、定义一个接口:

package com.zze.service;

public interface IWaiter {
    void service();
}
com.zze.service.IWaiter

2、定义它的实现类:

package com.zze.service.impl;

import com.zze.service.IWaiter;

public class Waiter implements IWaiter {
    public void service(){
        System.out.println("正在服务");
    }
}
com.zze.service.impl.Waiter

3、使用 JDK 提供的动态代理:

@Test
public void test() {
    IWaiter waiter = new Waiter();
    Class<?>[] interfaces = Waiter.class.getInterfaces();
    IWaiter waiterProxy = (IWaiter) Proxy.newProxyInstance(Waiter.class.getClassLoader(), interfaces, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object obj = null;
            if (method.getName().equalsIgnoreCase("service")) {
                System.out.println("服务之前");
                obj = method.invoke(waiter, args);
                System.out.println("服务之后");
            }
            return obj;
        }
    });
    waiterProxy.service();
    /*
    服务之前
    正在服务
    服务之后
    */
}

JDK 动态代理只能为实现了接口的类产生代理对象。

源码分析

从 newProxyInstance 方法看起:

 1 @CallerSensitive
 2 public static Object newProxyInstance(ClassLoader loader,
 3                                       Class<?>[] interfaces,
 4                                       InvocationHandler h)
 5         throws IllegalArgumentException
 6 {
 7     Objects.requireNonNull(h);
 8 
 9     final Class<?>[] intfs = interfaces.clone();
10     final SecurityManager sm = System.getSecurityManager();
11     if (sm != null) {
12         checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
13     }
14 
15     /*
16      * 生成代理类的 class 文件
17      */
18     Class<?> cl = getProxyClass0(loader, intfs);
19 
20 
21     try {
22         if (sm != null) {
23             checkNewProxyPermission(Reflection.getCallerClass(), cl);
24         }
25         /*
26          * 获取代理类构造函数
27          */
28         final Constructor<?> cons = cl.getConstructor(constructorParams);
29         final InvocationHandler ih = h;
30         if (!Modifier.isPublic(cl.getModifiers())) {
31             AccessController.doPrivileged(new PrivilegedAction<Void>() {
32                 public Void run() {
33                     cons.setAccessible(true);
34                     return null;
35                 }
36             });
37         }
38         /*
39         使用代理类的构造器,传入参数 h(即我们实现的InvocationHandler类实例)创建代理类的实例并返回
40          */
41         return cons.newInstance(new Object[]{h});
42     } catch (IllegalAccessException|InstantiationException e) {
43         throw new InternalError(e.toString(), e);
44     } catch (InvocationTargetException e) {
45         Throwable t = e.getCause();
46         if (t instanceof RuntimeException) {
47             throw (RuntimeException) t;
48         } else {
49             throw new InternalError(t.toString(), t);
50         }
51     } catch (NoSuchMethodException e) {
52         throw new InternalError(e.toString(), e);
53     }
54 }
java.lang.reflect.Proxy.newProxyInstance

该方法的返回值是第 41 行返回的代理类实例,而这个代理类字节码文件创建工作都是在 18 行的 getProxyClass0 方法完成:

1 private static Class<?> getProxyClass0(ClassLoader loader,
2     
3     // 如果被代理类实现的接口超出 65535 个则抛出异常
4     if (interfaces.length > 65535) {
5         throw new IllegalArgumentException("interface limit exceeded");
6     }
7     return proxyClassCache.get(loader, interfaces);
8 }
java.lang.reflect.Proxy.getProxyClass0

接着查看第 7 行 proxyClassCache.get 方法:

 1 public V get(K key, P parameter) {
 2         Objects.requireNonNull(parameter);
 3 
 4         expungeStaleEntries();
 5 
 6         Object cacheKey = CacheKey.valueOf(key, refQueue);
 7 
 8         ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
 9         if (valuesMap == null) {
10             ConcurrentMap<Object, Supplier<V>> oldValuesMap
11                 = map.putIfAbsent(cacheKey,
12                                   valuesMap = new ConcurrentHashMap<>());
13             if (oldValuesMap != null) {
14                 valuesMap = oldValuesMap;
15             }
16         }
17 
18         Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
19         Supplier<V> supplier = valuesMap.get(subKey);
20         Factory factory = null;
21 
22         while (true) {
23             if (supplier != null) {
24                 V value = supplier.get();
25                 if (value != null) {
26                     return value;
27                 }
28             }
29             
30             if (factory == null) {
31                 factory = new Factory(key, parameter, subKey, valuesMap);
32             }
33 
34             if (supplier == null) {
35                 supplier = valuesMap.putIfAbsent(subKey, factory);
36                 if (supplier == null) {
37                     supplier = factory;
38                 }
39             } else {
40                 if (valuesMap.replace(subKey, supplier, factory)) {
41                     supplier = factory;
42                 } else {
43                     supplier = valuesMap.get(subKey);
44                 }
45             }
46         }
47     }
java.lang.reflect.WeakCache.get

直接从 22 行开始看,入眼就是一个死循环,它的出口在 26 行,当 supplier.get() 不为空时返回它的值,而 supplier 的赋值操作是在第 34-38 行,赋值后就会执行 22 行 supplier.get 方法:

 1 @Override
 2 public synchronized V get() { 
 3     Supplier<V> supplier = valuesMap.get(subKey);
 4     if (supplier != this) {
 5         return null;
 6     }
 7 
 8     V value = null;
 9     try {
10         value = Objects.requireNonNull(valueFactory.apply(key, parameter));
11     } finally {
12         if (value == null) { 
13             valuesMap.remove(subKey, this);
14         }
15     }
16 
17     assert value != null;
18 
19     CacheValue<V> cacheValue = new CacheValue<>(value);
20 
21 
22     if (valuesMap.replace(subKey, this, cacheValue)) {
23 
24         reverseMap.put(cacheValue, Boolean.TRUE);
25     } else {
26         throw new AssertionError("Should not reach here");
27     }
28     return value;
29 }
java.lang.reflect.WeakCache.Factory.get

这个方法的返回值在第 10 行,它的值为 valueFactory.apply(key, parameter) 的返回值,而此时 valueFactory 是 java.lang.reflect.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         Class<?> interfaceClass = null;
 7         try {
 8             interfaceClass = Class.forName(intf.getName(), false, loader);
 9         } catch (ClassNotFoundException e) {
10         }
11         if (interfaceClass != intf) {
12             throw new IllegalArgumentException(
13                 intf + " is not visible from class loader");
14         }
15 
16         if (!interfaceClass.isInterface()) {
17             throw new IllegalArgumentException(
18                 interfaceClass.getName() + " is not an interface");
19         }
20         if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
21             throw new IllegalArgumentException(
22                 "repeated interface: " + interfaceClass.getName());
23         }
24     }
25 
26     String proxyPkg = null;     
27     int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
28 
29     for (Class<?> intf : interfaces) {
30         int flags = intf.getModifiers();
31         if (!Modifier.isPublic(flags)) {
32             accessFlags = Modifier.FINAL;
33             String name = intf.getName();
34             int n = name.lastIndexOf('.');
35             String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
36             if (proxyPkg == null) {
37                 proxyPkg = pkg;
38             } else if (!pkg.equals(proxyPkg)) {
39                 throw new IllegalArgumentException(
40                     "non-public interfaces from different packages");
41             }
42         }
43     }
44 
45     if (proxyPkg == null) {
46         proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
47     }
48 
49     long num = nextUniqueNumber.getAndIncrement();
50     String proxyName = proxyPkg + proxyClassNamePrefix + num;
51 
52     byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
53         proxyName, interfaces, accessFlags);
54     try {
55         return defineClass0(loader, proxyName,
56                             proxyClassFile, 0, proxyClassFile.length);
57     } catch (ClassFormatError e) {
58         throw new IllegalArgumentException(e.toString());
59     }
60 }
java.lang.reflect.Proxy.ProxyClassFactory.apply

从 26-47 行实际上就是在拼接代理类包名,保存在变量 proxyPkg 中,在 50 行拼接出代理类全路径。

此处 52 行的 ProxyGenerator.generateProxyClass 方法才是真正生成代理类字节码文件的地方,将其保存在名为 proxyClassFile 的字节数组中。查看 ProxyGenerator.generateProxyClass 方法:

 1 public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
 2         ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
 3         final byte[] var4 = var3.generateClassFile();
 4         if (saveGeneratedFiles) {
 5             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 6                 public Void run() {
 7                     try {
 8                         int var1 = var0.lastIndexOf(46);
 9                         Path var2;
10                         if (var1 > 0) {
11                             Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
12                             Files.createDirectories(var3);
13                             var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
14                         } else {
15                             var2 = Paths.get(var0 + ".class");
16                         }
17 
18                         Files.write(var2, var4, new OpenOption[0]);
19                         return null;
20                     } catch (IOException var4x) {
21                         throw new InternalError("I/O exception saving generated file: " + var4x);
22                     }
23                 }
24             });
25         }
26 
27         return var4;
28     }
sun.misc.ProxyGenerator.generateProxyClass

在第 3 行通过 generateClassFile 方法创建代理类字节码文件,保存在字节数组。查看 generateClassFile 方法:

  1 private byte[] generateClassFile() {
  2         this.addProxyMethod(hashCodeMethod, Object.class);
  3         this.addProxyMethod(equalsMethod, Object.class);
  4         this.addProxyMethod(toStringMethod, Object.class);
  5         Class[] var1 = this.interfaces;
  6         int var2 = var1.length;
  7 
  8         int var3;
  9         Class var4;
 10         for(var3 = 0; var3 < var2; ++var3) {
 11             var4 = var1[var3];
 12             Method[] var5 = var4.getMethods();
 13             int var6 = var5.length;
 14 
 15             for(int var7 = 0; var7 < var6; ++var7) {
 16                 Method var8 = var5[var7];
 17                 this.addProxyMethod(var8, var4);
 18             }
 19         }
 20 
 21         Iterator var11 = this.proxyMethods.values().iterator();
 22 
 23         List var12;
 24         while(var11.hasNext()) {
 25             var12 = (List)var11.next();
 26             checkReturnTypes(var12);
 27         }
 28 
 29         Iterator var15;
 30         try {
 31             this.methods.add(this.generateConstructor());
 32             var11 = this.proxyMethods.values().iterator();
 33 
 34             while(var11.hasNext()) {
 35                 var12 = (List)var11.next();
 36                 var15 = var12.iterator();
 37 
 38                 while(var15.hasNext()) {
 39                     ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
 40                     this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
 41                     this.methods.add(var16.generateMethod());
 42                 }
 43             }
 44 
 45             this.methods.add(this.generateStaticInitializer());
 46         } catch (IOException var10) {
 47             throw new InternalError("unexpected I/O Exception", var10);
 48         }
 49 
 50         if (this.methods.size() > 65535) {
 51             throw new IllegalArgumentException("method limit exceeded");
 52         } else if (this.fields.size() > 65535) {
 53             throw new IllegalArgumentException("field limit exceeded");
 54         } else {
 55             this.cp.getClass(dotToSlash(this.className));
 56             this.cp.getClass("java/lang/reflect/Proxy");
 57             var1 = this.interfaces;
 58             var2 = var1.length;
 59 
 60             for(var3 = 0; var3 < var2; ++var3) {
 61                 var4 = var1[var3];
 62                 this.cp.getClass(dotToSlash(var4.getName()));
 63             }
 64 
 65             this.cp.setReadOnly();
 66             ByteArrayOutputStream var13 = new ByteArrayOutputStream();
 67             DataOutputStream var14 = new DataOutputStream(var13);
 68 
 69             try {
 70                 var14.writeInt(-889275714);
 71                 var14.writeShort(0);
 72                 var14.writeShort(49);
 73                 this.cp.write(var14);
 74                 var14.writeShort(this.accessFlags);
 75                 var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
 76                 var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
 77                 var14.writeShort(this.interfaces.length);
 78                 Class[] var17 = this.interfaces;
 79                 int var18 = var17.length;
 80 
 81                 for(int var19 = 0; var19 < var18; ++var19) {
 82                     Class var22 = var17[var19];
 83                     var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
 84                 }
 85 
 86                 var14.writeShort(this.fields.size());
 87                 var15 = this.fields.iterator();
 88 
 89                 while(var15.hasNext()) {
 90                     ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
 91                     var20.write(var14);
 92                 }
 93 
 94                 var14.writeShort(this.methods.size());
 95                 var15 = this.methods.iterator();
 96 
 97                 while(var15.hasNext()) {
 98                     ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
 99                     var21.write(var14);
100                 }
101 
102                 var14.writeShort(0);
103                 return var13.toByteArray();
104             } catch (IOException var9) {
105                 throw new InternalError("unexpected I/O Exception", var9);
106             }
107         }
108     }
sun.misc.ProxyGenerator.generateClassFile

在起始 2-4 行可以看到,它还帮我们额外的代理了 hashCode、equals、toString 方法。
接着看 sun.misc.ProxyGenerator.generateProxyClass 的第 4 行,条件 saveGeneratedFiles 是一个布尔值,用于指定是否执行下面代码块的保存 class 文件到硬盘的功能,默认是 false。而 saveGeneratedFiles 的值实际上是取自

private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));

所以我们只要指定了它为 true,它就会帮我们保存字节码文件。

在 src 根目录下运行以下代码:

import com.zze.dao.impl.Waiter;
import com.zze.service.IWaiter;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        IWaiter waiter = new Waiter();
        Class<?>[] interfaces = Waiter.class.getInterfaces();
        IWaiter waiterProxy = (IWaiter) Proxy.newProxyInstance(Waiter.class.getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object obj = null;
                if (method.getName().equalsIgnoreCase("service")) {
                    System.out.println("服务之前");
                    obj = method.invoke(waiter, args);
                    System.out.println("服务之后");
                }
                return obj;
            }
        });
        waiterProxy.service();
    }
}
Test

接着在项目根目录下就会生成如下文件:

package com.sun.proxy;

import com.zze.service.IWaiter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements IWaiter {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(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 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 service() throws  {
        try {
            super.h.invoke(this, m3, (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);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.zze.service.IWaiter").getMethod("service");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
com.sun.proxy.$Proxy0

我们最后使用的代理对象就是 com.sun.proxy.$Proxy0 类的实例。

cglib动态代理

简介

CGLIB(Code Generation Library) 是一个开源项目!它是一个强大的,高性能,高质量的 Code 生成类库,它可以在运行期扩展 Java 类与实现 Java 接口。Hibernate 支持它来实现 PO(Persistent Object 持久化对象) 字节码的动态生成。

使用

1、引入 cglib 支持 jar,点击下载

2、编写被代理类:

package com.zze.service;

public class Waiter {
    public void service() {
        System.out.println("正在服务");
    }
}
com.zze.service.Waiter

3、使用 CGLIB 提供的动态代理:

@Test
public void test() {// 创建核心类对象
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Waiter.class);
    enhancer.setCallback(new MethodInterceptor() {
        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            // 判断方法是否是 save
            if ("service".equals(method.getName())) {
                // 增强,权限校验
                System.out.println("权限校验...");
            }
            return methodProxy.invokeSuper(o, args);
        }
    });
    Waiter customerDaoProxy = (Waiter) enhancer.create();
    customerDaoProxy.service();
}

 

转载于:https://www.cnblogs.com/zze46/p/10254480.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值