Javassist实现动态代理

Javassist实现动态代理

 

动态代理模式简述:之所以会出现代理这种模式就是因为我们常有这么一种需求:在被代理类的方法调用前后执行一些其它的逻辑,这些逻辑不适合由被代理类来实现,那这些逻辑谁来实现?当然是代理类。那代理类是谁?从哪里来?代理类是我们利用字节码生成工具动态创建的,然后利用反射实例化而得到代理对象。

 

tips:这篇文章讲的不是动态代理模式的思想而是怎么实现(简单实现)一个和java.lang.reflect.Proxy类相似的类。

 

按照JDK动态代理的套路来,先定义一个InvocationHandler来给客户端添加代理的逻辑(这个类和JDK中的一模一样):

 

 

Java代码 
  1. package cc.lixiaohui.demo.javassist.proxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. /** 
  6.  * @author lixiaohui 
  7.  * @date 2016年9月27日 下午9:53:59 
  8.  *  
  9.  */  
  10. public interface InvocationHandler {  
  11.       
  12.     /** 
  13.      * 业务逻辑填充 
  14.      *  
  15.      * @param proxy 生成的代理对象 
  16.      * @param method 调用的方法 
  17.      * @param args 调用该方法的参数 
  18.      * @return 调用该方法的返回值 
  19.      * @throws Throwable throws if any exception 
  20.      */  
  21.     Object invoke(Object proxy, Method method, Object[] args) throws Throwable;  
  22.       
  23. }  

 

 

接下来是Proxy类,代理类由该类动态生成并且都继承自该类,和JDK的一样,这也是为什么JDK的动态代理只能代理接口而不能代理父类,这里我就按照JDK的套路来,当然理解了这个后要实现代理父类也没什么难度了。Proxy类是怎么生成类的呢?首先代理的是接口,所以先遍历所有接口,再遍历接口的所有方法,为代理类生成与这些方法同签名同返回值的方法,也就是相当于实现(implement)这些接口的方法,至于生成过程具体是怎么样的我们不用管这也是用javassist的好处(字节码是怎么生成的是javassist的事,我们只需要用它的API即可)。

 

 

Java代码 
  1. package cc.lixiaohui.demo.javassist.proxy;  
  2.   
  3. import java.util.Objects;  
  4. import java.util.concurrent.atomic.AtomicInteger;  
  5.   
  6. import javassist.CannotCompileException;  
  7. import javassist.ClassPool;  
  8. import javassist.CtClass;  
  9. import javassist.CtConstructor;  
  10. import javassist.CtField;  
  11. import javassist.CtMethod;  
  12. import javassist.Modifier;  
  13. import javassist.NotFoundException;  
  14.   
  15. import org.slf4j.Logger;  
  16. import org.slf4j.LoggerFactory;  
  17.   
  18. import cc.lixiaohui.demo.javassist.proxy.util.CompoundKeyWeakHashMap;  
  19.   
  20. /** 
  21.  * 负责代理类类的生成 
  22.  *  
  23.  * <ul> 
  24.  * 生成的代理类: 
  25.  * <li>public final 修饰(和JDK动态代理不同的是:JDK生成的代理类也是final的, 但不一定是public的, 当所代理的接口中有至少一个以上的接口不是public时生成的代理就不是public的)</li> 
  26.  *  
  27.  * <li>类名以$Proxy为前缀, 后缀为数字, 如cc.lixiaohui.$Proxy0, cc.lixiaohui.$Proxy1...</li> 
  28.  *  
  29.  * <li>生成的代理类继承自{@link Proxy}</li> 
  30.  *  
  31.  * <li>生成的代理类所在package只有一种情况下才是确定的: 当所有接口中有且只有一个接口是non-public时.其他情况所在package不确定</li> 
  32.  * </ul> 
  33.  *   
  34.  * @author lixiaohui 
  35.  * @date 2016年9月27日 下午9:51:24 
  36.  *  
  37.  */  
  38. public class Proxy {  
  39.       
  40.     private static final Logger logger = LoggerFactory.getLogger(Proxy.class);  
  41.       
  42.     /** 
  43.      * 生成的代理类名前缀 
  44.      */  
  45.     private static final String PROXY_CLASSNAME_PREFIX = "$Proxy";  
  46.       
  47.     /** 
  48.      * 类后缀数字生成器 
  49.      */  
  50.     private static final AtomicInteger SUFFIX_GENERATOR = new AtomicInteger();   
  51.       
  52.     private static final boolean SHOULD_BE_FINAL = true;  
  53.     private static final boolean SHOULD_BE_ABSTRACT = false;  
  54.     private static final boolean SHOULD_BE_PUBLIC = true;  
  55.       
  56.     protected InvocationHandler invocationHandler;  
  57.       
  58.     /** 
  59.      * 弱引用已生成的Class的缓存, ClassLoader和被代理Class都相同时生成的代理Class才是相同的(这个类自己实现的,简单扩展一下java.util.Map就可以实现) 
  60.      * <类加载器, 被代理Class, 生成的代理Class> 
  61.      */  
  62.     private static CompoundKeyWeakHashMap<ClassLoader, Class<?>, Class<?>> proxyClassCache = new CompoundKeyWeakHashMap<ClassLoader, Class<?>, Class<?>>();  
  63.       
  64.     protected Proxy(InvocationHandler invocationHandler) {  
  65.         this.invocationHandler = invocationHandler;  
  66.     }  
  67.       
  68.     public static Object newProxyInstance(ClassLoader classLoader, Class<?> targetClass, InvocationHandler invocationHandler)   
  69.             throws Exception {  
  70.         // check not null  
  71.         classLoader = Objects.requireNonNull(classLoader, "classLoader cannot be null");  
  72.         targetClass = Objects.requireNonNull(targetClass, "targetClass cannot be null");  
  73.         invocationHandler = Objects.requireNonNull(invocationHandler, "invocationHandler cannot be null");  
  74.           
  75.         Class<?> proxyClass = proxyClassCache.get(classLoader, targetClass);  
  76.         // 有缓存  
  77.         if (proxyClass != null) {  
  78.             logger.debug("get proxy from cache");  
  79.             return proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler);  
  80.         }  
  81.           
  82.         // singleton instance of classpool   
  83.         ClassPool pool = ClassPool.getDefault();  
  84.         //生成代理类的全限定名  
  85.         String qualifiedName = generateQualifiedName(targetClass);  
  86.         // 创建代理类  
  87.         CtClass proxy = pool.makeClass(qualifiedName);  
  88.         // 设被代理类继承自Proxy  
  89.         setSuperClass(pool, proxy);  
  90.         // 获取被代理类的所有接口  
  91.         CtClass[] interfaces = pool.get(targetClass.getName()).getInterfaces();  
  92.           
  93.         int methodIndex = 0;  
  94.         // 遍历这些接口  
  95.         for (CtClass parent : interfaces) {  
  96.             proxy.addInterface(parent);  
  97.               
  98.             // 获取该接口的所有方法  
  99.             CtMethod[] methods = parent.getDeclaredMethods();  
  100.             for (int j = 0; j < methods.length; ++j) {  
  101.                 CtMethod method = methods[j];  
  102.                 String fieldSrc = String.format("private static java.lang.reflect.Method method%d = Class.forName(\"%s\").getDeclaredMethods()[%d];"  
  103.                         , methodIndex, parent.getName(), j);  
  104.                 logger.debug("field src for method {}: {}", method.getName(), fieldSrc);  
  105.                 // 生成字段  
  106.                 CtField ctField = CtField.make(fieldSrc, proxy);  
  107.                 // 添加字段  
  108.                 proxy.addField(ctField);  
  109.                 // 生成对应的Method  
  110.                 generateMethod(pool, proxy, method, methodIndex);  
  111.                   
  112.                 ++methodIndex;  
  113.             }  
  114.         }  
  115.         // 设置代理类的类修饰符  
  116.         setModifiers(proxy, SHOULD_BE_PUBLIC, SHOULD_BE_FINAL, SHOULD_BE_ABSTRACT);  
  117.         // 生成构造方法  
  118.         generateConstructor(pool, proxy);  
  119.         // 持久化class到硬盘, for use of debug  
  120.         proxy.writeFile(".");  
  121.         // to java.lang.Class  
  122.         proxyClass = proxy.toClass(classLoader, null);  
  123.         // 缓存  
  124.         proxyClassCache.put(classLoader, targetClass, proxyClass);  
  125.         return proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler);  
  126.     }  
  127.   
  128.     /** 
  129.      * 生成代理类的全限定名  
  130.      */  
  131.     private static String generateQualifiedName(Class<?> targetClass) throws Exception {  
  132.         CtClass theInterface = null;  
  133.         for (CtClass parent : ClassPool.getDefault().get(targetClass.getName()).getInterfaces()) {  
  134.             if (theInterface == null) {  
  135.                 theInterface = parent;  
  136.             }  
  137.             if (!Modifier.isPublic(parent.getModifiers())) {  
  138.                 theInterface = parent;  
  139.                 break;  
  140.             }  
  141.         }  
  142.         String name = theInterface.getPackageName() + "." + PROXY_CLASSNAME_PREFIX + SUFFIX_GENERATOR.getAndIncrement();  
  143.         return name;  
  144.     }  
  145.   
  146.   
  147.     /** 
  148.      * 设置类的修饰符 
  149.      */  
  150.     private static void setModifiers(CtClass proxy, boolean shouldBePublic, boolean shouldBeFinal, boolean shouldBeAbstract) {  
  151.         int modifier = 0;  
  152.         modifier = shouldBePublic ? modifier | Modifier.PUBLIC : modifier;  
  153.         modifier = shouldBeFinal ? modifier | Modifier.FINAL : modifier;  
  154.         modifier = shouldBeAbstract ? modifier | Modifier.ABSTRACT : modifier;  
  155.         logger.error(Modifier.toString(modifier));  
  156.         proxy.setModifiers(modifier);  
  157.     }  
  158.   
  159.     /** 
  160.      * 生成构造函数 
  161.      */  
  162.     private static void generateConstructor(ClassPool pool, CtClass proxy) throws NotFoundException, CannotCompileException {  
  163.         CtConstructor ctConstructor = new CtConstructor(new CtClass[]{pool.get(InvocationHandler.class.getName())}, proxy);  
  164.         String methodBodySrc = String.format("super(%s);""$1");  
  165.         logger.debug("constructor body for constructor {}: {}", ctConstructor.getName(), methodBodySrc);  
  166.         ctConstructor.setBody(methodBodySrc);  
  167.         proxy.addConstructor(ctConstructor);  
  168.     }  
  169.   
  170.   
  171.     /** 
  172.      * 生成代理方法 
  173.      */  
  174.     private static void generateMethod(ClassPool pool, CtClass proxy, CtMethod method, int methodIndex) throws NotFoundException, CannotCompileException {  
  175.         CtMethod ctMethod = new CtMethod(method.getReturnType(), method.getName(), method.getParameterTypes(), proxy);  
  176.         String methodBodySrc = String.format("return super.invocationHandler.invoke(this, method%d, $args);", methodIndex);  
  177.         logger.debug("method body for method {}: {}", method.getName(), methodBodySrc);  
  178.         ctMethod.setBody(methodBodySrc);  
  179.         proxy.addMethod(ctMethod);  
  180.     }  
  181.   
  182.     /** 
  183.      * 把proxy类的父类设置为Proxy 
  184.      *  
  185.      */  
  186.     private static void setSuperClass(ClassPool pool, CtClass proxy) throws CannotCompileException, NotFoundException {  
  187.         proxy.setSuperclass(pool.get(Proxy.class.getName()));  
  188.     }  
  189.   
  190. }  

 

 

使用测试

 使用方式和JDK的没啥区别

先定义两个被代理的接口:

 

Java代码 
  1. package cc.lixiaohui.demo.javassist.proxy.example;  
  2.   
  3. public interface Talkable {   
  4.     Object talk(String words) throws Exception;   
  5. }  

 

Java代码 
  1. package cc.lixiaohui.demo.javassist.proxy.example;  
  2.   
  3. interface Smileable {  
  4.     Object smile() throws Exception;  
  5. }  

 

Person实现上面两接口:

 

Java代码 
  1. package cc.lixiaohui.demo.javassist.proxy.example;  
  2.   
  3. public class Person implements Smileable, Talkable {  
  4.   
  5.     private String name;  
  6.       
  7.     public Person(String name) {  
  8.         this.name = name;  
  9.     }  
  10.       
  11.     public Object talk(String words) throws Exception {  
  12.         System.out.println(name + " says: " + words);  
  13.         return words;  
  14.     }  
  15.       
  16.     public Object smile() throws Exception {  
  17.         System.out.println(name + " start smiling");  
  18.         System.out.println(name + " stop smiling");  
  19.         return null;  
  20.     }  
  21.   
  22. }  

 

 

代理逻辑的实现:

 

Java代码 
  1. package cc.lixiaohui.demo.javassist.proxy.example;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import cc.lixiaohui.demo.javassist.proxy.InvocationHandler;  
  6. import cc.lixiaohui.demo.javassist.proxy.Proxy;  
  7.   
  8. public class JavassistProxyFactory implements InvocationHandler{  
  9.   
  10.     //被代理类的对象  
  11.     private Object target;  
  12.       
  13.     public JavassistProxyFactory(Object target) {  
  14.         this.target = target;  
  15.     }  
  16.       
  17.     /*  
  18.      * @see cc.lixiaohui.demo.javassist.proxy.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 
  19.      */  
  20.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  21.         System.out.println("------- intercept before --------");  
  22.                 // 调用原来的方法  
  23.         Object result = method.invoke(target, args);  
  24.         System.out.println("--------intercept after ---------");  
  25.         return result;  
  26.     }  
  27.     // 获取代理类的对象  
  28.     public Object getProxy() throws Exception {  
  29.         return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass(), this);  
  30.     }  
  31.       
  32. }  

 

测试主程序:

Java代码 
  1. package cc.lixiaohui.demo.javassist.proxy.example;  
  2.   
  3. import java.lang.reflect.Modifier;  
  4.   
  5. import org.junit.Test;  
  6.   
  7. public class Tester {  
  8.       
  9.     @Test  
  10.     public void testJavassist() throws Exception {  
  11.         Person person = new Person("小明");  
  12.         Object proxy = new JavassistProxyFactory(person).getProxy();  
  13.                 // System.gc(); // 主动触发gc  
  14.         Object proxy1 = new JavassistProxyFactory(person).getProxy();  
  15.         ((Talkable) proxy).talk("hello world");  
  16.         ((Smileable) proxy).smile();  
  17.           
  18.         System.out.println("package: " + proxy.getClass().getPackage().getName());  
  19.         System.out.println("classname: " + proxy.getClass().getName());  
  20.         System.out.println("modifiers: " + Modifier.toString(proxy.getClass().getModifiers()));  
  21.                 System.out.println(proxy.getClass() == proxy1.getClass()); // 测试缓存是否起作用  
  22.     }  
  23.   
  24. }  

 

结果输出:


 
 

 

在 Proxy类中生成代理Class时把这个Class持久化了到硬盘中,通过反编译工具查看生成的代理类的源码:

 

Java代码 
  1. /*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao ([email protected]) ***/  
  2. package cc.lixiaohui.demo.javassist.proxy.example;  
  3.   
  4. import cc.lixiaohui.demo.javassist.proxy.InvocationHandler;  
  5. import cc.lixiaohui.demo.javassist.proxy.Proxy;  
  6. import java.lang.reflect.Method;  
  7.   
  8. public final class $Proxy0 extends Proxy implements Smileable, Talkable {  
  9.     private static Method method0 = java.lang.Class.forName("cc.lixiaohui.demo.javassist.proxy.example.Smileable").getDeclaredMethods()[0];  
  10.     private static Method method1 = java.lang.Class.forName("cc.lixiaohui.demo.javassist.proxy.example.Talkable").getDeclaredMethods()[0];  
  11.   
  12.     public Object smile() {  
  13.         return this.invocationHandler.invoke(this, method0, new Object[0]);  
  14.     }  
  15.   
  16.     public Object talk(String paramString) {  
  17.         return this.invocationHandler.invoke(this, method1, new Object[] { paramString });  
  18.     }  
  19.   
  20.     public $Proxy0(InvocationHandler paramInvocationHandler) {  
  21.         super(paramInvocationHandler);  
  22.     }  
  23. }  

你可能感兴趣的:(设计模式,动态代理,代理,javassist)