美文网首页
0424-java反射/动态代理(spring ioc用到

0424-java反射/动态代理(spring ioc用到

作者: 小咕咕coco | 来源:发表于2020-04-24 22:10 被阅读0次

    反射

    反射机制就是,java运行时环境中的,动态自观自调能力:

    • 对于任意一个类,可以知道这个类有哪些属性和方法
    • 对于任意一个对象,可以调用它的任意一个方法,知道它所属的类

    具体:(使用方法,原理等
    参见链接:https://www.zhihu.com/question/24304289/answer/694344906

    代理

    代理要实现的是:原类的封装与功能添加(比如在项目现有所有类的方法前后打印日志。

    在不修改原代码前提下实现方法:

    1. 编写一个新类,实现和目标类相同的接口+添加新的功能,
    2. 实例化时:目标对象实例作为参数传入构造方法,代理对象的内部方法都通过调用目标类中对应的方法实现

    此为静态代理

    动态代理:如何动态实现这个过程?(即动态构造代理类并实例化

    首先看一下常规的实例创建过程:

    • classloader加载.class文件到内存,读取字节码,生成class对象
      ——class对象是class类的实例,包含了一个类的所有信息,比如构造器、方法、字段等
    • 内存分配,构造器调用,生成对应的实例

    动态实现代理,关键在于,如何获取代理类的class对象?(之前是手动创的代理类,加载时生成的class对象

    ——class对象的信息从哪获取?

    :1. 接口拥有代理对象和目标对象共同的类信息

    代理类和目标类理应实现同一组接口。
    之所以实现相同接口,是为了尽可能保证代理对象的内部结构和目标对象一致,
    这样我们对代理对象的操作最终都可以转移到目标对象身上,代理对象只需专注于增强代码的编写
    
    1. 但是接口是无法创建对象的

    ——JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,实现了类对象构造,进而动态代理

    1. Proxy类:构造类对象
    • Proxy的静态方法:getProxyClass(ClassLoader, interfaces),传入类加载器和接口,返回代理Class对象
      • 把接口中的类信息到一个,带有构造器的,新的class对象,然后返回
    • 有了class对象之后,得到constructor(构造器),创建代理实例
    1. InvocationHandler类(代理和目标之间的桥梁
    • 代理Class的构造器创建对象时,需要传入InvocationHandler
    • 每次调用代理对象的方法,最终都会通过调用InvocationHandler的invoke()方法,转移到目标对象上(invoke()方法需要根据目标对象重写
    public class ProxyTest {
        public static void main(String[] args) throws Throwable {
            CalculatorImpl target = new CalculatorImpl();
                    //传入目标对象
                    //目的:1.根据它实现的接口生成代理对象 2.代理对象调用目标对象方法
            Calculator calculatorProxy = (Calculator) getProxy(target);
            calculatorProxy.add(1, 2);
            calculatorProxy.subtract(2, 1);
        }
    
        private static Object getProxy(final Object target) throws Exception {
            //参数1:随便找个类加载器给它, 参数2:目标对象实现的接口,让代理对象实现相同接口
            Class proxyClazz = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
            Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
            Object proxy = constructor.newInstance(new InvocationHandler() {
                @Override
          //重写invoke
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println(method.getName() + "方法开始执行...");
                    Object result = method.invoke(target, args);
                    System.out.println(result);
                    System.out.println(method.getName() + "方法执行结束...");
                    return result;
                }
            });
            return proxy;
        }
    }
    
    • 不过实际编程中,一般不用getProxyClass(),而是使用Proxy类的另一个静态方法:Proxy.newProxyInstance(),直接返回代理实例,连中间得到代理Class对象的过程都帮你隐藏:
    public class ProxyTest {
        public static void main(String[] args) throws Throwable {
            CalculatorImpl target = new CalculatorImpl();
            Calculator calculatorProxy = (Calculator) getProxy(target);
            calculatorProxy.add(1, 2);
            calculatorProxy.subtract(2, 1);
        }
    
        private static Object getProxy(final Object target) throws Exception {
            Object proxy = Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),/*类加载器*/
                    target.getClass().getInterfaces(),/*让代理对象和目标对象实现相同接口*/
                    new InvocationHandler(){/*代理对象的方法最终都会被JVM导向它的invoke方法*/
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println(method.getName() + "方法开始执行...");
                            Object result = method.invoke(target, args);
                            System.out.println(result);
                            System.out.println(method.getName() + "方法执行结束...");
                            return result;
                        }
                    }
            );
            return proxy;
        }
    }
    

    参考:
    https://www.zhihu.com/question/20794107/answer/658139129

    相关文章

      网友评论

          本文标题:0424-java反射/动态代理(spring ioc用到

          本文链接:https://www.haomeiwen.com/subject/sktcwhtx.html