自己实现JDK的Proxy
2017-01-09 16:09
155 查看
1.动态代理,就是在运行期间动态生成一个代理类,通过代理类来调用我们主题类的方法(本文不讲动态代理模式,要自己先了解清楚)。所以首先我们得搞清楚怎么动态生成类,这里我用到的是jdk自带的javax.tools里面的 JavaCompiler等工具。
2.动态生成类,下面是我封装好的一个工具代码:
测试上面工具类:
3.下面根据jdk的proxy简单实现下,注意是简单实现,不包括jdk的优化代理类缓存等。(ps:jdk动态生成类的技术肯定不是用的上述动态生成类的技术,我们这里只是模拟思想)
首先上jdk的InvocationHandler
重要角色Proxy类
好了,jdk的工具实现完了,下面来举个代理模式的例子:
今天就到这里,谢谢大家!
老生常谈:深圳有爱好音乐的会打鼓(吉他,键盘,贝斯等)的程序员和其它职业可以一起交流加入我们乐队一起嗨。我的QQ:657455400
2.动态生成类,下面是我封装好的一个工具代码:
public class CompilerTool { /** * 编译生成class类对象 * @param packageName 包名 * @param className class文件的名称 * @param classContent java代码内容 * @return */ public static Class<?> compiler(String packageName , String className , String javaSrcContent){ // 生成源代码的JavaFileObject SimpleJavaFileObject fileObject = new JavaSourceFromString( className, javaSrcContent); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 被修改后的JavaFileManager JavaFileManager fileManager = new ClassFileManager( compiler.getStandardFileManager(null, null, null)); // 执行编译 JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, Arrays.asList(fileObject)); task.call(); // 获得ClassLoader,加载class文件 ClassLoader classLoader = fileManager.getClassLoader(null); try { String c = packageName+"."+className ; return classLoader.loadClass(c); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null ; } static class JavaSourceFromString extends SimpleJavaFileObject { final String code; JavaSourceFromString(String name, String code) { super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); this.code = code; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; } } static class JavaClassFileObject extends SimpleJavaFileObject { // 用于存储class字节 ByteArrayOutputStream outputStream; public JavaClassFileObject(String className, Kind kind) { super(URI.create("string:///" + className.replace('.', '/') + kind.extension), kind); outputStream = new ByteArrayOutputStream(); } @Override public OutputStream openOutputStream() throws IOException { return outputStream; } public byte[] getClassBytes() { return outputStream.toByteArray(); } } @SuppressWarnings("rawtypes") static class ClassFileManager extends ForwardingJavaFileManager { private JavaClassFileObject classFileObject; @SuppressWarnings("unchecked") protected ClassFileManager(JavaFileManager fileManager) { super(fileManager); } @Override public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { classFileObject = new JavaClassFileObject(className, kind); return classFileObject; } @Override // 获得一个定制ClassLoader,返回我们保存在内存的类 public ClassLoader getClassLoader(Location location) { return new ClassLoader() { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classBytes = classFileObject.getClassBytes(); return super .defineClass(name, classBytes, 0, classBytes.length); } }; } } }
测试上面工具类:
public static void main(String[] args) throws InstantiationException, IllegalAccessException { String java = "public class Aa{static{System.out.println(\"aaaa被动态加载了\");}}" ; Class<?> aa = CompilerTool.compiler("Aa", java) ; aa.newInstance(); } //结果:aaaa被动态加载了
3.下面根据jdk的proxy简单实现下,注意是简单实现,不包括jdk的优化代理类缓存等。(ps:jdk动态生成类的技术肯定不是用的上述动态生成类的技术,我们这里只是模拟思想)
首先上jdk的InvocationHandler
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object... args) throws Exception; }
重要角色Proxy类
public class Proxy{ public static Object newProxyInstance(InvocationHandler invocationHandler , Class<?>[] interfaces){ //代理类的随机名称 String targetName = "$Proxy"+new Random().nextInt(10); // 存储 代理类 的 java代码字符串 StringBuilder proxyContent = new StringBuilder(); //--------- 包名 : package 抽象主题接口的包 一致 proxyContent.append("package "+interfaces[0].getPackage().getName() + ";"); //--------- import 的一些必须 for(Class<?> clazz : interfaces){ proxyContent.append("import ").append(clazz.getName()).append(';'); } proxyContent.append("import java.lang.reflect.Method;"); //--------- 头部 : public class $Proxy implements xxx1,xx2{ proxyContent.append("public class ").append(targetName).append(" implements "); for(int i=0;i<interfaces.length;i++){ if(i == interfaces.length - 1){ // 最后一个 proxyContent.append(interfaces[i].getSimpleName()); break; } proxyContent.append(interfaces[i].getSimpleName()).append(","); } proxyContent.append("{") ; //---------成员变量 InvocationHandler handler ; proxyContent.append("InvocationHandler handler;"); //---------构造函数 proxyContent.append("public ").append(targetName).append("(InvocationHandler handler){this.handler=handler;}") ; // 一个接口一个接口找 for(Class<?> inter : interfaces){ //---------要实现的所有的方法,看抽象主题接口,有什么就都要实现 for(Method method :inter.getDeclaredMethods()){ method.setAccessible(true) ; proxyContent.append("public ").append(method.getReturnType().getName()).append(' '); proxyContent.append(method.getName()).append('('); // 构造 方法参数列表 Class<?>[] parameterTypes = method.getParameterTypes() ; String ps = null ; for(int i=0;i<parameterTypes.length;i++){ if(i == parameterTypes.length - 1){ proxyContent.append(parameterTypes[i].getName()).append(" p").append(i); ps += "p"+i; c454 break; } proxyContent.append(parameterTypes[i].getName()).append(" p").append(i).append(","); ps += "p"+i+","; } // 方法里面 得反射调用 客户端 主题接口 的实现类 的 同样的方法 proxyContent.append("){try{").append("Method md="+inter.getName()+".class.getMethod(\""+method.getName()+"\");"); if(ps == null){ proxyContent.append("this.handler.invoke(this,"+"md"+");}catch(Exception e){e.printStackTrace();}}"); }else{ proxyContent.append("this.handler.invoke(this,"+"md"+ps+");}catch(Exception e){e.printStackTrace();}}"); } } } proxyContent.append('}'); System.out.println(proxyContent); Object proxy = null ; //代理对象 try { Class<?> pClass = CompilerTool.compiler(interfaces[0].getPackage().getName(),targetName, proxyContent.toString()) ; // 调用上面动态 类的 构造器 , 生成代理类对象 proxy = pClass.getDeclaredConstructor(InvocationHandler.class).newInstance(invocationHandler); } catch (Exception e) { e.printStackTrace(); } return proxy; } } //上面字符串拼接的类实际上是生成了类似下面格式的类(假如随机名称是$Proxy5,包名:test.proxy,主题接口名:HttpSubject,主题接口只有一个方法:http,下面会有例子): package test.proxy; import test.proxy.HttpSubject; import java.lang.reflect.Method; public class $Proxy5 implements HttpSubject { InvocationHandler handler; public $Proxy5tt(InvocationHandler handler) { this.handler = handler; } public void http() { try { Method md = test.proxy.HttpSubject.class.getMethod("http"); this.handler.invoke(this, md); } catch (Exception e) { e.printStackTrace(); } } }
好了,jdk的工具实现完了,下面来举个代理模式的例子:
//这个使我们要代理 的 抽象主题 public interface HttpSubject{ public void http(); } //抽象主题的实现类 class HttpSubjectImpl implements HttpSubject{ @Override public void http() { System.out.println("=========http========"); } } //动态代理 class DynamicSubject implements InvocationHandler{ Object subject ; public DynamicSubject(Object subject ) { this.subject = subject ; } @Override public Object invoke(Object proxy, Method method, Object... args) throws Exception { return method.invoke(subject, args); } } //测试 public static void main(String[] args) throws Exception { HttpSubject subject = new HttpSubjectImpl(); InvocationHandler handler = new DynamicSubject(subject); long start = System.currentTimeMillis(); HttpSubject proxy = (HttpSubject) Proxy.newProxyInstance(handler, subject.getClass().getInterfaces()); System.out.println("动态生成时间:"+ (System.currentTimeMillis()-start)); proxy.http(); } //测试结果:(时间太长了) 动态生成时间:641 =========http========
今天就到这里,谢谢大家!
老生常谈:深圳有爱好音乐的会打鼓(吉他,键盘,贝斯等)的程序员和其它职业可以一起交流加入我们乐队一起嗨。我的QQ:657455400
相关文章推荐
- 15_传智播客Spring2.5视频教程_使用JDK中的Proxy技术实现AOP功能 2
- 使用JDK中的Proxy技术实现AOP功能[动态代理]
- 使用JDK中的Proxy技术实现AOP功能
- Spring(十)通过动态代理(JDK的Proxy)和cglib实现AOP技术
- 容器第三课,JDK源码分析,自己实现ArrayList数组扩容
- ITCAST视频-Spring学习笔记(使用JDK中的Proxy技术实现AOP功能)
- Mac下ProxyChains Tor实现shell代理,隐藏自己的ssh登陆ip
- JDK中的Proxy技术实现AOP功能
- JDK中的Proxy技术实现AOP功能
- JDK集合分析Set和Map的关系(自己实现Set到Map的扩展)
- AOP_1.入门及使用JDK中的Proxy技术实现
- 使用JDK中的proxy技术实现AOP功能
- JDK使用InvocationHandler和Proxy实现动态代理
- JDK中Proxy实现切面编程
- 利用JDK提供的Proxy类和cglib.jar实现Aop功能
- 15_传智播客Spring2.5视频教程_使用JDK中的Proxy技术实现AOP功能 3
- 编码实现用JDK中的Proxy实现springAOP功能
- (8) 使用JDK中的Proxy技术实现AOP功能 以及 CGLIB生成代理
- 使用JDK中的Proxy技术来实现动态代理
- 自己写一个java.lang.reflect.Proxy代理的实现