Javassist实现动态代理

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

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

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

package cc.lixiaohui.demo.javassist.proxy;  

import java.lang.reflect.Method;  

/** 
 * @author lixiaohui 
 * @date 2016年9月27日 下午9:53:59 
 *  
 */  
public interface InvocationHandler {  

    /** 
     * 业务逻辑填充 
     *  
     * @param proxy 生成的代理对象 
     * @param method 调用的方法 
     * @param args 调用该方法的参数 
     * @return 调用该方法的返回值 
     * @throws Throwable throws if any exception 
     */  
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;  

}  

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

package cc.lixiaohui.demo.javassist.proxy;  

import java.util.Objects;  
import java.util.concurrent.atomic.AtomicInteger;  

import javassist.CannotCompileException;  
import javassist.ClassPool;  
import javassist.CtClass;  
import javassist.CtConstructor;  
import javassist.CtField;  
import javassist.CtMethod;  
import javassist.Modifier;  
import javassist.NotFoundException;  

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  

import cc.lixiaohui.demo.javassist.proxy.util.CompoundKeyWeakHashMap;  

/** 
 * 负责代理类类的生成 
 *  
 * <ul> 
 * 生成的代理类: 
 * <li>public final 修饰(和JDK动态代理不同的是:JDK生成的代理类也是final的, 但不一定是public的, 当所代理的接口中有至少一个以上的接口不是public时生成的代理就不是public的)</li> 
 *  
 * <li>类名以$Proxy为前缀, 后缀为数字, 如cc.lixiaohui.$Proxy0, cc.lixiaohui.$Proxy1...</li> 
 *  
 * <li>生成的代理类继承自{@link Proxy}</li> 
 *  
 * <li>生成的代理类所在package只有一种情况下才是确定的: 当所有接口中有且只有一个接口是non-public时.其他情况所在package不确定</li> 
 * </ul> 
 *   
 * @author lixiaohui 
 * @date 2016年9月27日 下午9:51:24 
 *  
 */  
public class Proxy {  

    private static final Logger logger = LoggerFactory.getLogger(Proxy.class);  

    /** 
     * 生成的代理类名前缀 
     */  
    private static final String PROXY_CLASSNAME_PREFIX = "$Proxy";  

    /** 
     * 类后缀数字生成器 
     */  
    private static final AtomicInteger SUFFIX_GENERATOR = new AtomicInteger();   

    private static final boolean SHOULD_BE_FINAL = true;  
    private static final boolean SHOULD_BE_ABSTRACT = false;  
    private static final boolean SHOULD_BE_PUBLIC = true;  

    protected InvocationHandler invocationHandler;  

    /** 
     * 弱引用已生成的Class的缓存, ClassLoader和被代理Class都相同时生成的代理Class才是相同的(这个类自己实现的,简单扩展一下java.util.Map就可以实现) 
     * <类加载器, 被代理Class, 生成的代理Class> 
     */  
    private static CompoundKeyWeakHashMap<ClassLoader, Class<?>, Class<?>> proxyClassCache = new CompoundKeyWeakHashMap<ClassLoader, Class<?>, Class<?>>();  

    protected Proxy(InvocationHandler invocationHandler) {  
        this.invocationHandler = invocationHandler;  
    }  

    public static Object newProxyInstance(ClassLoader classLoader, Class<?> targetClass, InvocationHandler invocationHandler)   
            throws Exception {  
        // check not null  
        classLoader = Objects.requireNonNull(classLoader, "classLoader cannot be null");  
        targetClass = Objects.requireNonNull(targetClass, "targetClass cannot be null");  
        invocationHandler = Objects.requireNonNull(invocationHandler, "invocationHandler cannot be null");  

        Class<?> proxyClass = proxyClassCache.get(classLoader, targetClass);  
        // 有缓存  
        if (proxyClass != null) {  
            logger.debug("get proxy from cache");  
            return proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler);  
        }  

        // singleton instance of classpool   
        ClassPool pool = ClassPool.getDefault();  
        //生成代理类的全限定名  
        String qualifiedName = generateQualifiedName(targetClass);  
        // 创建代理类  
        CtClass proxy = pool.makeClass(qualifiedName);  
        // 设被代理类继承自Proxy  
        setSuperClass(pool, proxy);  
        // 获取被代理类的所有接口  
        CtClass[] interfaces = pool.get(targetClass.getName()).getInterfaces();  

        int methodIndex = 0;  
        // 遍历这些接口  
        for (CtClass parent : interfaces) {  
            proxy.addInterface(parent);  

            // 获取该接口的所有方法  
            CtMethod[] methods = parent.getDeclaredMethods();  
            for (int j = 0; j < methods.length; ++j) {  
                CtMethod method = methods[j];  
                String fieldSrc = String.format("private static java.lang.reflect.Method method%d = Class.forName(\"%s\").getDeclaredMethods()[%d];"  
                        , methodIndex, parent.getName(), j);  
                logger.debug("field src for method {}: {}", method.getName(), fieldSrc);  
                // 生成字段  
                CtField ctField = CtField.make(fieldSrc, proxy);  
                // 添加字段  
                proxy.addField(ctField);  
                // 生成对应的Method  
                generateMethod(pool, proxy, method, methodIndex);  

                ++methodIndex;  
            }  
        }  
        // 设置代理类的类修饰符  
        setModifiers(proxy, SHOULD_BE_PUBLIC, SHOULD_BE_FINAL, SHOULD_BE_ABSTRACT);  
        // 生成构造方法  
        generateConstructor(pool, proxy);  
        // 持久化class到硬盘, for use of debug  
        proxy.writeFile(".");  
        // to java.lang.Class  
        proxyClass = proxy.toClass(classLoader, null);  
        // 缓存  
        proxyClassCache.put(classLoader, targetClass, proxyClass);  
        return proxyClass.getConstructor(InvocationHandler.class).newInstance(invocationHandler);  
    }  

    /** 
     * 生成代理类的全限定名  
     */  
    private static String generateQualifiedName(Class<?> targetClass) throws Exception {  
        CtClass theInterface = null;  
        for (CtClass parent : ClassPool.getDefault().get(targetClass.getName()).getInterfaces()) {  
            if (theInterface == null) {  
                theInterface = parent;  
            }  
            if (!Modifier.isPublic(parent.getModifiers())) {  
                theInterface = parent;  
                break;  
            }  
        }  
        String name = theInterface.getPackageName() + "." + PROXY_CLASSNAME_PREFIX + SUFFIX_GENERATOR.getAndIncrement();  
        return name;  
    }  


    /** 
     * 设置类的修饰符 
     */  
    private static void setModifiers(CtClass proxy, boolean shouldBePublic, boolean shouldBeFinal, boolean shouldBeAbstract) {  
        int modifier = 0;  
        modifier = shouldBePublic ? modifier | Modifier.PUBLIC : modifier;  
        modifier = shouldBeFinal ? modifier | Modifier.FINAL : modifier;  
        modifier = shouldBeAbstract ? modifier | Modifier.ABSTRACT : modifier;  
        logger.error(Modifier.toString(modifier));  
        proxy.setModifiers(modifier);  
    }  

    /** 
     * 生成构造函数 
     */  
    private static void generateConstructor(ClassPool pool, CtClass proxy) throws NotFoundException, CannotCompileException {  
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{pool.get(InvocationHandler.class.getName())}, proxy);  
        String methodBodySrc = String.format("super(%s);", "$1");  
        logger.debug("constructor body for constructor {}: {}", ctConstructor.getName(), methodBodySrc);  
        ctConstructor.setBody(methodBodySrc);  
        proxy.addConstructor(ctConstructor);  
    }  


    /** 
     * 生成代理方法 
     */  
    private static void generateMethod(ClassPool pool, CtClass proxy, CtMethod method, int methodIndex) throws NotFoundException, CannotCompileException {  
        CtMethod ctMethod = new CtMethod(method.getReturnType(), method.getName(), method.getParameterTypes(), proxy);  
        String methodBodySrc = String.format("return super.invocationHandler.invoke(this, method%d, $args);", methodIndex);  
        logger.debug("method body for method {}: {}", method.getName(), methodBodySrc);  
        ctMethod.setBody(methodBodySrc);  
        proxy.addMethod(ctMethod);  
    }  

    /** 
     * 把proxy类的父类设置为Proxy 
     *  
     */  
    private static void setSuperClass(ClassPool pool, CtClass proxy) throws CannotCompileException, NotFoundException {  
        proxy.setSuperclass(pool.get(Proxy.class.getName()));  
    }  

}  

使用测试

使用方式和JDK的没啥区别

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

package cc.lixiaohui.demo.javassist.proxy.example;  

public interface Talkable {   
    Object talk(String words) throws Exception;   
}  
package cc.lixiaohui.demo.javassist.proxy.example;  

interface Smileable {  
    Object smile() throws Exception;  
}  

Person实现上面两接口:

package cc.lixiaohui.demo.javassist.proxy.example;  

public class Person implements Smileable, Talkable {  

    private String name;  

    public Person(String name) {  
        this.name = name;  
    }  

    public Object talk(String words) throws Exception {  
        System.out.println(name + " says: " + words);  
        return words;  
    }  

    public Object smile() throws Exception {  
        System.out.println(name + " start smiling");  
        System.out.println(name + " stop smiling");  
        return null;  
    }  

}  

代理逻辑的实现:

package cc.lixiaohui.demo.javassist.proxy.example;  

import java.lang.reflect.Method;  

import cc.lixiaohui.demo.javassist.proxy.InvocationHandler;  
import cc.lixiaohui.demo.javassist.proxy.Proxy;  

public class JavassistProxyFactory implements InvocationHandler{  

    //被代理类的对象  
    private Object target;  

    public JavassistProxyFactory(Object target) {  
        this.target = target;  
    }  

    /*  
     * @see cc.lixiaohui.demo.javassist.proxy.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 
     */  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        System.out.println("------- intercept before --------");  
                // 调用原来的方法  
        Object result = method.invoke(target, args);  
        System.out.println("--------intercept after ---------");  
        return result;  
    }  
    // 获取代理类的对象  
    public Object getProxy() throws Exception {  
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass(), this);  
    }  

}  

测试主程序:

package cc.lixiaohui.demo.javassist.proxy.example;  

import java.lang.reflect.Modifier;  

import org.junit.Test;  

public class Tester {  

    @Test  
    public void testJavassist() throws Exception {  
        Person person = new Person("小明");  
        Object proxy = new JavassistProxyFactory(person).getProxy();  
                // System.gc(); // 主动触发gc  
        Object proxy1 = new JavassistProxyFactory(person).getProxy();  
        ((Talkable) proxy).talk("hello world");  
        ((Smileable) proxy).smile();  

        System.out.println("package: " + proxy.getClass().getPackage().getName());  
        System.out.println("classname: " + proxy.getClass().getName());  
        System.out.println("modifiers: " + Modifier.toString(proxy.getClass().getModifiers()));  
                System.out.println(proxy.getClass() == proxy1.getClass()); // 测试缓存是否起作用  
    }  

}  

结果输出:
这里写图片描述

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

/*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao (cnfree2000@hotmail.com) ***/  
package cc.lixiaohui.demo.javassist.proxy.example;  

import cc.lixiaohui.demo.javassist.proxy.InvocationHandler;  
import cc.lixiaohui.demo.javassist.proxy.Proxy;  
import java.lang.reflect.Method;  

public final class $Proxy0 extends Proxy implements Smileable, Talkable {  
    private static Method method0 = java.lang.Class.forName("cc.lixiaohui.demo.javassist.proxy.example.Smileable").getDeclaredMethods()[0];  
    private static Method method1 = java.lang.Class.forName("cc.lixiaohui.demo.javassist.proxy.example.Talkable").getDeclaredMethods()[0];  

    public Object smile() {  
        return this.invocationHandler.invoke(this, method0, new Object[0]);  
    }  

    public Object talk(String paramString) {  
        return this.invocationHandler.invoke(this, method1, new Object[] { paramString });  
    }  

    public $Proxy0(InvocationHandler paramInvocationHandler) {  
        super(paramInvocationHandler);  
    }  
}  

转载自http://lixiaohui.iteye.com/blog/2328182

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值