• java动态代理机制之自定义实现动态代理


    
    

      

      Spring的开发方式之一就是面向切面编程即AOP,AOP的核心构造是切面,它将那些影响多个类的行为封装到可重用的模块中。而AOP的原理就是java的动态代理机制。

      本篇主要通过自定义一个Proxy类,来更深刻的理解动态代理的机制和原理。

      每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:

    public interface SelfInvocationHandler {
        /**
         *
         * @param proxy 指代我们所代理的那个真实对象
         * @param method 指代的是我们所要调用真实对象的某个方法的Method对象
         * @param args  指代的是调用真实对象某个方法时接受的参数
         * @return
         * @throws Throwable
         */
        public Object invoke(Object proxy, Method method,Object[] args) throws Throwable ;
    
    }
    

      Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

    import javax.tools.JavaCompiler;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    /**
     * 自定义代理类
     */
    public class SelfProxy {
        private static String ln = "
    ";
        /**
         *
         * @param interfaces
         * @return
         */
        private static String generateStr(Class<?> interfaces) {
            StringBuffer src = new StringBuffer();
            src.append("package com.BXD._08Reflect.self;" + ln);
            src.append("import java.lang.reflect.Method;" + ln);
            src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
            src.append("SelfInvocationHandler h;" + ln);
    
            src.append("public $Proxy0(SelfInvocationHandler h){" + ln);
            src.append("this.h=h;" + ln);
            src.append("}" + ln);
            for (Method m : interfaces.getMethods()
                    ) {
                src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
                src.append("try{");
                src.append("Method m=" + interfaces.getName() + ".class.getMethod("" + m.getName() + "", new Class[]{});" + ln);
                src.append("this.h.invoke(this,m,null);" + ln);
                src.append("}" + ln);
                src.append("catch(Throwable throwable){" + ln);
                src.append("throwable.printStackTrace();" + ln);
                src.append("}");
                src.append("}" + ln);
            }
    
            src.append("}");
            return src.toString();
        }
    
        /**
         *  Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象
         * @param loader 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
         * @param interfaces  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
         * @param h  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
         * @return
         * @throws IOException
         * @throws ClassNotFoundException
         * @throws NoSuchMethodException
         * @throws IllegalAccessException
         * @throws InvocationTargetException
         * @throws InstantiationException
         */
        public static Object newProxyInstance(SelfClassLoad loader, Class<?>[] interfaces, SelfInvocationHandler h) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
            //1.生成源代码
            String proxySrc = generateStr(interfaces[0]);
            //2.将生成的源代码输出到磁盘,保存为,java文件
            String filePath = SelfProxy.class.getResource("").getPath();
            File javaFile = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(javaFile);
            fw.write(proxySrc);
            fw.flush();
            fw.close();
            //3.编译源代码,并且生成.class文件
            JavaCompiler compiler= ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager=compiler.getStandardFileManager(null,null,null);
        
            Iterable iterable=manager.getJavaFileObjects(javaFile);
            JavaCompiler.CompilationTask task=compiler.getTask(null,manager,null,null,null,iterable);
            task.call();
            manager.close();
            //4.将class文件中的内容,动态加载到JVM中来
            Class proxyClass = loader.findClass("$Proxy0");
            //5.返回被代理后的代理对象
            Constructor c=proxyClass.getConstructor(SelfInvocationHandler.class);
            javaFile.delete();
            return c.newInstance(h);
        }
    }
    

      自定义ClassLoad类,用来将动态生成的.class文件加载到JVM中

    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /**
     * Created by Administrator on 2018/6/23.
     * ClassLoader对象,对动态生成的.class文件加载到JVM
     */
    public class SelfClassLoad extends ClassLoader{
        private File baseDir;
    
        /**
         *
         */
        public SelfClassLoad() {
            String basePath=SelfClassLoad.class.getResource("").getPath();
            this.baseDir=new File(basePath);
        }
    
        @Override
        protected Class<?> findClass(String name)  {
            String className = SelfClassLoad.class.getPackage().getName() + "." + name;
            if (baseDir!=null){
                File classFile=new File(baseDir,name.replace("\.","/")+".class");
                if (classFile.exists()){
                    FileInputStream in=null;
                    ByteArrayOutputStream out=null;
                    try {
                        in=new FileInputStream(classFile);
                        out=new ByteArrayOutputStream();
                        byte[] buff=new byte[1024];
                        int len;
                        while ((len=in.read(buff))!=-1){
                            out.write(buff,0,len);
                        }
    
                        return defineClass(className,out.toByteArray(),0,out.size());
                    }catch (Exception e){
                        e.printStackTrace();
                    }finally {
    
                        if (null!=in){
                            try {
                                in.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if (null!=out){
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        classFile.delete();
                    }
                }
            }
            return null;
        }
    }
    

      定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外

    **
     * Created by Administrator on 2018/6/23.
     * 定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口
     */
    public class Meipo implements SelfInvocationHandler {
    
        /**
         * 这个就是我们要代理的真实对象
         */
        private Person target;
        public Object getInstance(Person target) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
            this.target=target;
            Class clazz=target.getClass();
            System.out.println("被代理对象的class是:"+clazz);
            return new SelfProxy().newProxyInstance(new SelfClassLoad(),clazz.getInterfaces(),this);
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //在代理真实对象前我们可以添加一些自己的操作
            System.out.println("我是媒婆");
            System.out.println("开始相亲。。。。");
            //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
            method.invoke(this.target,args);
            System.out.println("结束相亲.......");
            return null;
        }
    }
    

      

    public interface Person {
        //相亲
        void findLove();
    }
    

      

    public class XiaoXingXing  implements Person{
        @Override
        public void findLove() {
            System.out.println("相亲要求");
            System.out.println("高富帅");
            System.out.println("有房车");
        }
    }
    

      

    /**
     * 自定义动态代理
     */
    public class Test {
        public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
            Person xingxign=(Person)new Meipo().getInstance(new XiaoXingXing());
            System.out.println(xingxign);
            xingxign.findLove();
    
        }
    }
      
    

      

  • 相关阅读:
    [好程序员训练营]Objective-C学习笔记---基本数据结构NSNumber
    [好程序员训练营]Objective-C学习笔记---基本数据结构NSDictionary
    [好程序员训练营]Objective-C学习笔记--基本数据结构NSArray
    [好程序员训练营]Objective-C学习笔记---基本数据结构NSString
    [好程序员训练营]Objective-C学习笔记---点语法
    [好程序员训练营]Objective-C学习笔记---构造函数和析构函数
    【好程序员训练营】Objective-C学习笔记----------成员变量和成员函数的封装
    【好程序员训练营】Objective-C学习笔记______类和对象的使用
    【好程序员训练营】Objective-C学习笔记(类的声明)NO1
    React Native 手工搭建环境 之iOS篇
  • 原文地址:https://www.cnblogs.com/gousheng107/p/9222961.html
Copyright © 2020-2023  润新知