自定义实现Java动态代理
Posted hangzhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义实现Java动态代理相关的知识,希望对你有一定的参考价值。
转自:https://www.cnblogs.com/rjzheng/p/8750265.html
一 借助JDK的API实现:
1.先创建一个接口,并实现它
public interface Person { void eat(); }
public class PersonImpl implements Person {
@Override
public void eat() {
System.out.println("eat............");
}
}
2.实现InvocationHandler:每一个动态代理类都要实现这个接口
1 public class PersonInvocationHandler implements InvocationHandler { 2 3 //我们要代理的真实对象 4 private Object obj; 5 6 public PersonInvocationHandler(Object obj) { 7 this.obj = obj; 8 } 9 10 /** 11 * Object proxy: 12 * 1. 可以使用反射获取代理对象的信息(也就是proxy.getClass().getName())。 13 * 2. 可以将代理对象返回以进行连续调用,这就是proxy存在的目的,因为this并不是代理对象。 14 */ 15 @Override 16 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 17 System.out.println("before eat......."); 18 //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 19 method.invoke(obj, args); 20 System.out.println("after eat......."); 21 return null; 22 } 23 }
3.测试
1 public class JdkTest { 2 public static void main(String[] args) { 3 PersonInvocationHandler personInvocationHandler = new PersonInvocationHandler(new PersonImpl()); 4 5 Person personProxy = (Person) Proxy.newProxyInstance(PersonImpl.class.getClassLoader(), 6 PersonImpl.class.getInterfaces(), personInvocationHandler); 7 8 personProxy.eat(); 9 } 10 }
返回结果:
二 自定义动态代理
1.自定义InvocationHandler
1 public interface MyInvocationHandler { 2 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; 3 }
2.实现自定义的MyInvocationHandler
1 public class PersonInvocationHandler implements MyInvocationHandler { 2 3 //我们要代理的真实对象 4 private Object obj; 5 6 public PersonInvocationHandler(Object obj) { 7 this.obj = obj; 8 } 9 10 /** 11 * Object proxy: 12 * 1. 可以使用反射获取代理对象的信息(也就是proxy.getClass().getName())。 13 * 2. 可以将代理对象返回以进行连续调用,这就是proxy存在的目的,因为this并不是代理对象。 14 */ 15 @Override 16 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 17 System.out.println("before eat......."); 18 //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 19 method.invoke(obj, args); 20 System.out.println("after eat......."); 21 return null; 22 } 23 }
3.自定义ClassLoader
1 public class MyClassLoader extends ClassLoader{ 2 3 private File classPathFile; 4 5 public MyClassLoader() { 6 String classPath = MyClassLoader.class.getResource("").getPath(); 7 this.classPathFile = new File(classPath); 8 } 9 10 public Class<?> findClass(String name) { 11 String className = MyClassLoader.class.getPackage().getName() + "." + name; 12 if (classPathFile != null){ 13 File file = new File(classPathFile, name + ".class"); 14 FileInputStream inputStream = null; 15 ByteArrayOutputStream outputStream = null; 16 try { 17 inputStream = new FileInputStream(file); 18 outputStream = new ByteArrayOutputStream(); 19 byte[] buf = new byte[1024]; 20 int len ; 21 while ((len = inputStream.read(buf)) != -1){ 22 outputStream.write(buf, 0, len); 23 } 24 return defineClass(className, outputStream.toByteArray(), 0, outputStream.size()); 25 }catch (Exception e){ 26 e.printStackTrace(); 27 }finally { 28 if(null!=inputStream){ 29 try { 30 inputStream.close(); 31 } catch (IOException e) { 32 // TODO Auto-generated catch block 33 e.printStackTrace(); 34 } 35 } 36 if(null!=outputStream){ 37 try { 38 outputStream.close(); 39 } catch (IOException e) { 40 // TODO Auto-generated catch block 41 e.printStackTrace(); 42 } 43 } 44 } 45 } 46 return null; 47 } 48 }
4.自定义Proxy代理类
主要流程:1.将源码输入到Java文件
2.将Java文件编译成class文件
3.将class加载进jvm
4.返回代理类对象
public class MyProxy { public static final String ln = "\\r\\n"; public static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler handler) { try { //1.java源码 String src = generateSrc(interfaces); //2.将源码输出到Java文件中 String filePath = MyProxy.class.getResource("").getPath(); System.out.println(filePath); File file = new File(filePath + "$Proxy0.java"); FileWriter fw = new FileWriter(file); fw.write(src); fw.flush(); fw.close(); //3.将Java文件编译成class文件 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manager = javaCompiler.getStandardFileManager(null, null, null); Iterable iterable = manager.getJavaFileObjects(file); JavaCompiler.CompilationTask task = javaCompiler.getTask(null, manager, null, null,null, iterable); task.call(); manager.close(); //4.将class加载进jvm Class proxyClass = classLoader.findClass("$Proxy0"); file.delete(); //5.返回代理类对象 Constructor constructor = proxyClass.getConstructor(MyInvocationHandler.class); return constructor.newInstance(handler); }catch (Exception e){ e.printStackTrace(); } return null; } //Java源码 private static String generateSrc(Class<?>[] interfaces) { // TODO Auto-generated method stub StringBuffer sb = new StringBuffer(); sb.append("package xin.hangzhi.jdk.proxy.demo.custom;" + ln); sb.append("import java.lang.reflect.Method;" + ln); sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln); sb.append("private MyInvocationHandler h;"+ln); sb.append("public $Proxy0(MyInvocationHandler h) { " + ln); sb.append("this.h = h;"+ln); sb.append("}" + ln); for (Method m : interfaces[0].getMethods()) { sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln); sb.append("try{" + ln); sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\\"" + m.getName() + "\\",new Class[]{});" + ln); sb.append("this.h.invoke(this,m,null);" + ln); sb.append("}catch(Throwable e){" + ln); sb.append("e.printStackTrace();" + ln); sb.append("}"+ln); sb.append("}"+ln); } sb.append("}" + ln); return sb.toString(); } }
5.测试结果
以上是关于自定义实现Java动态代理的主要内容,如果未能解决你的问题,请参考以下文章