粗略实现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) { } }}
阅读全文
1 0
- 粗略实现jdk中的接口动态代理
- 动态代理1 (JDK 需要实现接口)
- jdk动态代理接口
- JDK中的动态代理
- JDK中的动态代理
- JDK中的动态代理
- JDK中的动态代理
- jdk中的动态代理
- JDK中的动态代理
- JDK中的动态代理
- JDK中的动态代理
- AOP实现--JDK中的动态代理和cglib代理
- JDK动态代理实现
- jdk动态代理实现
- 实现jdk动态代理
- jdk动态代理实现
- jdk实现动态代理
- JDK实现动态代理
- JavaScript最佳新手入门系列之(同步与异步)
- bzoj 1227: [SDOI2009]虔诚的墓主人
- ubuntu12.04 配置openGL ES2.0 开发环境
- 文件系统对性能的影响
- 我的第一篇CSDN
- 粗略实现jdk中的接口动态代理
- java设置环境变量
- 写给大一大二大三还在迷惘中的学生
- JSONP学习笔记
- C++ pair的用法
- 动态链接库DLL基础知识
- Mac系统nginx 安装与配置
- problems During Content Assist
- ES6对于let和const的认识