粗略实现jdk中的接口动态代理

来源:互联网 发布:淘宝上印度德玛药房 编辑:程序博客网 时间:2024/06/06 21:16

学习了下代理设计模式对jdk中的动态代理感到好奇是怎么实现的,于是查看了类加载器,动态编译以及jdk动态代理原理资料试着实现了一下

一 核心代码1:生成代理代理对象类 两个核心方法,newProxyInstance用于产生代理对象,generateJavaSourceByTemplate用于生成源代码字符串

public class MyProxy {private static String className;private static String initPackageName = "com.colin.proxy";/** * 产生代理对象方法 * @param classLoader 传入被代理类的类加载器 * @param interfaces 传入代理类实现的接口 * @param invocationHandler 传入invocationHandler对象 * @return 返回生成的代理对象 */public static Object newProxyInstance(ClassLoader classLoader,Class[] interfaces,InvocationHandler invocationHandler) {//产生源码String source = generateJavaSourceByTemplate(null, interfaces);//将源码编译try {Class<?> c = DynamicCompilerRAM.compiler(source, className, initPackageName+"."+className,classLoader);//返回代理对象Constructor constructor = c.getConstructor(InvocationHandler.class);Object object = constructor.newInstance(invocationHandler);System.out.println("代理对象:"+object);return object;} catch (Exception e) {e.printStackTrace();System.out.println("生成代理对象出错");}return null;}/** * 产生源码字符串 * @param packageName 包名 * @param interfaces 接口数组 * @return 返回源码 */private static String generateJavaSourceByTemplate(String packageName,Class[] interfaces) {className = "$proxy"+interfaces.hashCode();//生成类名if(packageName!=null&&!"".equals(packageName)) {//如果不指定包的名字,默认使用initPackageName = packageName;}//组装java源码StringBuilder sb = new StringBuilder();sb.append("package "+initPackageName+";");sb.append("public class "+className+" implements ");sb.append(interfaces[0].getName());//拼接实现接口for(int i=1;i<interfaces.length;i++) {sb.append(","+interfaces[i].getName());}//建立构造函数 必须传入一个InvocationHandlersb.append("{");sb.append("private classaboutproxy.InvocationHandler invocationHandler;");sb.append("public "+className+"(classaboutproxy.InvocationHandler invocationHandler)"+ "{this.invocationHandler=invocationHandler;}");//实现接口里面的方法for (Class clazz : interfaces) {Method[] ms = clazz.getMethods();for (Method method : ms) {Class[] parameterTypes = method.getParameterTypes();//拼接参数类型class数组 为后面获取方法做准备StringBuilder psb = null;if(parameterTypes.length>0) {psb = new StringBuilder();psb.append("new Class[]{"+parameterTypes[0].getName()+".class");for (int i=1;i<parameterTypes.length;i++) {psb.append(","+parameterTypes[i].getName()+".class");}psb.append("}");}//method.getModifiers();可以获取修饰符的int值,下面偷懒了 统一写成publicsb.append("public "+method.getReturnType().getName() +" "+method.getName()+"(");for (int i =0;i<parameterTypes.length;i++) {if(i==parameterTypes.length-1) {sb.append(parameterTypes[i].getName()+" arg"+i);break;}sb.append(parameterTypes[i].getName()+" arg"+i+",");}sb.append("){");//方法体 实际上调用的是invocationhandler中的方法sb.append("try{");//将method对象传入到invocationHandler.invoke();中if(parameterTypes.length>0) {sb.append("Object obj = invocationHandler.invoke(this,"+clazz.getName()+".class.getMethod(\""+method.getName()+"\","+psb.toString()+")");} else {sb.append("Object obj = invocationHandler.invoke(this,"+clazz.getName()+".class.getMethod(\""+method.getName()+"\")");}for (int i =0;i<parameterTypes.length;i++) {sb.append(" ,arg"+i);}sb.append(");");//如果返回结果不是void 返回方法执行的结果if(!"void".equals(method.getReturnType().getName())) {sb.append("return ("+method.getReturnType().getName()+")obj;");}sb.append("}");sb.append("catch(Exception e){}");if(!"void".equals(method.getReturnType().getName())) {sb.append("return null;");}sb.append("}");}}sb.append("}");System.out.println(sb.toString());return sb.toString();}}

二 核心代码2  在内存中编译源代码并加载class字节码文件

public class DynamicCompilerRAM {    public static Class compiler(String javaSource,String className,String entireClassName,ClassLoader classLoader) throws Exception {    /*         * 编译内存中的java代码         * */        // 1.将代码写入内存中        StringWriter writer = new StringWriter(); // 内存字符串输出流        PrintWriter out = new PrintWriter(writer);        out.println(javaSource);        out.flush();        out.close();                // 2.开始编译        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();        JavaFileObject fileObject = new StringJavaObject(className, writer.toString());//        CompilationTask task = javaCompiler.getTask(null, null, null, Arrays.asList("-d","./bin"), null, Arrays.asList(fileObject));        boolean success = task.call();        if (!success) {            System.out.println("编译失败");        }else{            System.out.println("编译成功");        }       // URL[] urls = new URL[]{new URL("file:/" + "./bin/")};        //URLClassLoader urlClassLoader = new URLClassLoader(urls);        Class classl =classLoader.loadClass(entireClassName);        return classl;    }}

三 测试效果

1 先准备一个接口和一个实现类

public interface Test{public void f();public void f2(String s);public String f3(String input);}public class TestProxy implements Test {private String name;public TestProxy(String name) {this.name = name;}@Overridepublic void f() {System.out.println("我是被代理对象!"+name+"!");}@Overridepublic void f2(String s) {System.out.println("我实现了基本的动态代理"+s);}@Overridepublic String f3(String input) {return input;}}
2 开始测试

public class Main {public static void main(String[] args) throws Exception{//测试代理TestProxy testProxy = new TestProxy("testProxy");Test t=(Test) MyProxy.newProxyInstance(testProxy.getClass().getClassLoader(), testProxy.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke( Object obj,Method method, Object...args){try {System.out.println("方法执行前!");Object o = method.invoke(testProxy, args);//具体执行这个方法的任然是原来的对象//System.out.println(obj);System.out.println("方法执行后");return o;} catch (Exception e) {e.printStackTrace();}return null;}});t.f();t.f2("哈哈");String s = t.f3("输入字符串");System.out.println(s);}}


3 测试效果
编译成功
代理对象:com.colin.proxy.$proxy366712642@28feb3fa
方法执行前!
我是被代理对象!testProxy!
方法执行后
方法执行前!
我实现了基本的动态代理哈哈
方法执行后
方法执行前!
方法执行后
输入字符串
4 动态编译生成的代理对象源码

public class $proxy366712642 implements classaboutproxy.Test {    private classaboutproxy.InvocationHandler invocationHandler;    public $proxy366712642(classaboutproxy.InvocationHandler invocationHandler) {        this.invocationHandler = invocationHandler;    }    public java.lang.String f3(java.lang.String arg0) {        try {            Object obj = invocationHandler.invoke(this,                    classaboutproxy.Test.class.getMethod("f3",                        new Class[] { java.lang.String.class }), arg0);            return (java.lang.String) obj;        } catch (Exception e) {        }        return null;    }    public void f() {        try {            Object obj = invocationHandler.invoke(this,                    classaboutproxy.Test.class.getMethod("f"));        } catch (Exception e) {        }    }    public void f2(java.lang.String arg0) {        try {            Object obj = invocationHandler.invoke(this,                    classaboutproxy.Test.class.getMethod("f2",                        new Class[] { java.lang.String.class }), arg0);        } catch (Exception e) {        }    }}
原创粉丝点击