0424-java反射/动态代理(spring ioc用到
2020-04-24 本文已影响0人
小咕咕coco
反射
反射机制就是,java运行时环境中的,动态自观自调能力:
- 对于任意一个类,可以知道这个类有哪些属性和方法
- 对于任意一个对象,可以调用它的任意一个方法,知道它所属的类
具体:(使用方法,原理等
参见链接:https://www.zhihu.com/question/24304289/answer/694344906
代理
代理要实现的是:原类的封装与功能添加(比如在项目现有所有类的方法前后打印日志。
在不修改原代码前提下实现方法:
- 编写一个新类,实现和目标类相同的接口+添加新的功能,
- 实例化时:目标对象实例作为参数传入构造方法,代理对象的内部方法都通过调用目标类中对应的方法实现
此为静态代理
动态代理:如何动态实现这个过程?(即动态构造代理类并实例化
首先看一下常规的实例创建过程:
- classloader加载.class文件到内存,读取字节码,生成class对象
——class对象是class类的实例,包含了一个类的所有信息,比如构造器、方法、字段等 - 内存分配,构造器调用,生成对应的实例
动态实现代理,关键在于,如何获取代理类的class对象?(之前是手动创的代理类,加载时生成的class对象
——class对象的信息从哪获取?
:1. 接口拥有代理对象和目标对象共同的类信息
代理类和目标类理应实现同一组接口。
之所以实现相同接口,是为了尽可能保证代理对象的内部结构和目标对象一致,
这样我们对代理对象的操作最终都可以转移到目标对象身上,代理对象只需专注于增强代码的编写
- 但是接口是无法创建对象的
——JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,实现了类对象构造,进而动态代理
:
- Proxy类:构造类对象
- Proxy的静态方法:getProxyClass(ClassLoader, interfaces),传入类加载器和接口,返回代理Class对象
- 把接口中的类信息到一个,带有构造器的,新的class对象,然后返回
- 有了class对象之后,得到constructor(构造器),创建代理实例
- 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