一个简单JDK版动态代理
本文实例为大家分享了手动实现的一个简单JDK版动态代理,供大家参考,具体内容如下
一.实现步骤
1.根据目标类的接口类型生成代理类的java文件。
2.编译代理类java文件为.class字节码文件。
3.将编译好的字节码文件加载到jvm中。
4.生成代理类对象并返回。
二.代码实现
1.Proxy类
public class CLProxy { private static final String ENTER= "\r\n"; private static final String PAKAGE=CLProxy.class.getPackage().toString()+";"; private static final String CLASS_NAME="$Proxy"; private static final AtomicInteger NUMBER= new AtomicInteger(0); public static Object newProxyInstance(CLClassLoader classLoader, Class<?>[] interfaces,CLInvocationHandler h) throws Exception{ String className =CLASS_NAME+NUMBER.getAndIncrement(); //遍历所有的接口生成java 文件 String javaString = createJavaString(interfaces, className); String parentPath = CLProxy.class.getResource("").getPath(); File file =new File(parentPath,className+".java" ); FileWriter writer = new FileWriter(file); writer.write(javaString); writer.flush(); writer.close(); //System.out.println(file); //编译 JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null); Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file); JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects); task.call(); standardFileManager.close(); //创建实例 Class<?> aClass = classLoader.findClass(className); Constructor<?> constructor = aClass.getConstructor(CLInvocationHandler.class); Object instance = constructor.newInstance(h); //file.delete(); return instance; } /** * 生成java 文件 * @param interfaces * @return */ private static String createJavaString(Class<?>[] interfaces , String className ){ StringBuffer buffer = new StringBuffer(); buffer.append(PAKAGE+ENTER); buffer.append("import java.lang.reflect.Method;"+ ENTER); StringBuffer interfaceString= new StringBuffer(); int length= interfaces.length; for (int i = 0; i<length ; ++i){ interfaceString.append(interfaces[i].getName()); if (i!=length-1){ interfaceString.append(","); } } buffer.append("public final class "); buffer.append(className); buffer.append(" implements "); buffer.append(interfaceString); buffer.append(" {"+ENTER); buffer.append("private CLInvocationHandler handler;"+ENTER); buffer.append("public "+className+"(CLInvocationHandler handler) {"+ENTER); buffer.append(" this.handler= handler;"+ENTER); buffer.append("}"+ENTER); for (int i =0 ;i<length;++i){ Class<?> clazz= interfaces[i]; Method[] methods = clazz.getMethods(); for (Method method : methods){ String returnTypeString = method.getReturnType().getName(); Class<?>[] parameterTypes = method.getParameterTypes(); StringBuffer paramTypeString = new StringBuffer(); StringBuffer methodParamString = new StringBuffer(); StringBuffer invokeParamString = new StringBuffer(); paramTypeString.append("new Class[]{"); int paramLength= parameterTypes.length; for (int j =0 ; j<paramLength ;++j){ Class<?> paramClazz= parameterTypes[j]; paramTypeString.append(paramClazz.getName()+".class"); String paramFieldName = "var"+j; methodParamString.append(paramClazz.getName() +" "+paramFieldName); invokeParamString.append(paramFieldName); if (j!= paramLength-1){ paramTypeString.append(","); methodParamString.append(","); invokeParamString.append(","); } } paramTypeString.append("}"); int modifiers = method.getModifiers(); if (Modifier.isPublic(modifiers)){ buffer.append("public"); }else if (Modifier.isPrivate(modifiers)){ buffer.append("private"); }else if (Modifier.isProtected(modifiers)){ buffer.append("protected"); } buffer.append(" final "+returnTypeString+" "+ method.getName()+"("+methodParamString+"){"+ ENTER); buffer.append("try{"+ENTER); buffer.append("Method method = "+clazz.getName()+".class.getMethod(\""+method.getName()+"\","+paramTypeString+" );"+ENTER); if (!"void".equals(returnTypeString)){ buffer.append("return ("+returnTypeString+")"); } if (invokeParamString.toString().length()==0){ invokeParamString.append("null"); }else{ invokeParamString = new StringBuffer("new Object[]{"+invokeParamString.toString()+"}"); } buffer.append("this.handler.invoke(this,method,"+invokeParamString+");"+ENTER); buffer.append("}catch(Throwable e){"+ENTER); buffer.append("e.printStackTrace();"+ENTER); buffer.append("}"+ENTER); if (!"void".equals(returnTypeString)){ buffer.append("return null;"+ENTER); } buffer.append("}"+ENTER); } } buffer.append("}"); return buffer.toString(); } public static void main(String[] args) throws Exception { Person person = (Person)CLProxy.newProxyInstance(new CLClassLoader(), XiaoMing.class.getInterfaces(), new CLInvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"); Object result= method.invoke(new XiaoMing(), args); System.out.println("after"); return result; } }); String laoxu = person.call("laoxu"); System.out.println(laoxu); /* person.eat(); Class<?>[] interfaces = person.getClass().getInterfaces(); for (Class<?> in:interfaces){ System.out.println(in.getName()); } */ Person person2= (Person)CLProxy.newProxyInstance(new CLClassLoader(), XiaoMing.class.getInterfaces(), new CLInvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"); Object result= method.invoke(new XiaoMing(), args); System.out.println("after"); return result; } }); System.out.println(person2.getClass()); } }
2.InvocationHandler接口
public interface CLInvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
3.ClassLoader类加载器
public class CLClassLoader extends ClassLoader { private File classPathFile; public CLClassLoader(){ String classPath = CLClassLoader.class.getResource("").getPath(); this.classPathFile= new File(classPath); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String className = CLClassLoader.class.getPackage().getName()+"."+name; if (classPathFile!= null ){ File classFile = new File(classPathFile, name.replace("\\.", "/") + ".class"); if (classFile.exists()){ FileInputStream inputStream =null; ByteArrayOutputStream outputStream = null; try{ inputStream=new FileInputStream(classFile); outputStream= new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int len; while ((len=inputStream.read(bytes))!=-1){ outputStream.write(bytes,0,len); } return defineClass(className,outputStream.toByteArray(),0,outputStream.size()); }catch (Exception e){ e.printStackTrace(); }finally { if (inputStream!= null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (outputStream!=null){ try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } } return super.findClass(name); } }
4.测试使用的接口与目标类
//测试使用的接口 public interface Person { void eat(); String call(String name); } //测试使用目标类 public class XiaoMing implements Person { @Override public void eat() { System.out.println("吃东西"); } //@Override public String call(String name) { return name; } }
注意测试方法在CLProxy 的main 方法中。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
Java的字符读写类CharArrayReader和CharArrayWriter使用示例
这篇文章主要介绍了Java的字符读写类CharArrayReader和CharArrayWriter使用示例,两个类分别继承于Reader和Writer,需要的朋友可以参考下2016-06-06Java多线程之scheduledThreadPool的方法解析
这篇文章主要介绍了Java多线程之scheduledThreadPool的方法解析,queue是DelayedWorkQueue,但通过后面的分析可以知道,最大线程数是不起作用的,最多会起核心线程数的数量,需要的朋友可以参考下2023-12-12Java中的NumberFormatException异常原因以及解决方案详解
这篇文章主要介绍了Java中的NumberFormatException异常原因以及解决方案详解,NumberFormatException 是 Java 中的一个异常类,通常在字符串转换为数字的过程中发生,它表示一个无效的数字格式,即字符串无法被正确解析为数字,需要的朋友可以参考下2024-02-02springboot @PostConstruct无效的解决
这篇文章主要介绍了springboot @PostConstruct无效的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-11-11
最新评论