zoukankan      html  css  js  c++  java
  • 自定义实现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 = "
    ";
    
        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.测试结果

  • 相关阅读:
    使用了Theme但是没有效果问题
    4.0 流量控制preference
    android sdk国内目录http://mirrors.neusoft.edu.cn/android/repository/
    xmpp push篇一 广播消息
    cursorfilter
    android 特效UI实现
    Android四大组件一----Activity
    net user命令
    sql2005如何附加数据库
    sql2005中如何启用SA账号
  • 原文地址:https://www.cnblogs.com/hangzhi/p/9234604.html
Copyright © 2011-2022 走看看