在我自己的学习过程中,动态代理是比较难理解的一部分,对知识的掌握情况决定了对某些问题见解的角度和深度会不一样,所以我今天站在小白的角度对动态代理做一个分享。
前情提要:
在说动态代理之前,先简要复习两个知识点:
- JVM类加载机制
- JAVA反射
类加载:
JVM的类加载过程分为五个部分:
1.加载
2.验证
3.准备
4.解析
5.初始化
在类加载之前,得先由JAVA编译器把Java类文件编译成.class字节码文件,然后JVM中才能开始执行加载过程,加载的过程JVM干了三件比较重要的事情:
1.JVM通过一个类的全类名找到这个类对应的.class文件
2.将二进制字节流里储存的静态结构转换为方法区中运行时的储存结构(java.lang.Class对象)
给我们的提示是,想要加载一个类,前提是得有.class字节码文件。
反射:
这里不对反射的内部机制做过多描述,只是简单说一下反射。反射按我的理解来看就是通过一个类的类对象(java.lang.class对象)来获取类的一切(类的名字、属性、方法、构造器),用思维导图简要呈现一下:
静态代理:
静态代理的组成部分:
1.接口I;
- I的实现类A;
3.一对一为实现类A生成一个代理B,有用靶向精准代理的感觉,以下三个部分的代码对应我刚刚说的(1)(2)(3)。
public interface Person {
void dance();
}
public class PersonImpl implements Person {
public void dance(){
System.out.println("旋转");
}
}
public class PersonImplStaticProxy {
private PersonImpl person;
public PersonImplStaticProxy(PersonImpl person){
this.person= person;
}
public void dance(){
person.dance();
}
}
小结:
(1)静态代理的实现思路:
代理类B跟实现类A实现相同的接口,并将A作为B的成员字段,只需调用A里面的方法就可以了。
(2)静态代理的优点:
其实也算是代理的优点,在不改变A代码的基础上,为A增加功能,能再调用A的前后增加很多其他的方法。
(3)静态代理的缺点:
如果接口的实现类有很多个,那么这种一对一绑定生成代理的模式将会产生很多低效且重复的工作。
那么有什么高效的机制呢?
动态代理:
话不多说,先把刚刚动态代理的代码贴在下面
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonHandler implements InvocationHandler {
private Object objectTarget;
public PersonHandler(Object objectTarget){
this.objectTarget = objectTarget;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println("我被调用啦");
System.out.println("在这里灵活的装饰接口方法");
return method.invoke(objectTarget,args);
}
}
import java.lang.reflect.Proxy;
public class PersonDynamicProxy {
public static void main(String[] args) {
Person p = new PersonImpl();
PersonHandler proxy = new PersonHandler(p);
Person p1 =(Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),
new Class<?>[]{Person.class}, proxy);
p1.dance();
}
}
第一段代码生成的是PersonHandler类,它实现了InvocationHandler这个反射里的接口,里面的invoke(Object proxy, Method method, Object[] args)方法,三个参数:
1.Object proxy:代理对象。
2.Method method:被调用的代理对象的方法名。
3.Object[] args:被调用的代理对象的方法的参数。
想一想之前说的反射,反射里有个method.invoke()方法,它是对反射里实现方法调用的一步。PersonHandler类就相当于一个灵活的框架,其实从名字也都能看出来,它只是一个handler,是一个中间商,它实现了委托类和代理类的解绑,但又能在invoke方法中对委托类进行功能的加强,也是委托类和目标类的一个桥梁。
第二段代码PersonDynamicProxy类,这里的关键在Proxy.newProxyInstance(proxy.getClass().getClassLoader(),
new Class<?>[]{Person.class}, proxy)这一步是为了获得一个代理对象的实例,三个参数:
1.proxy.getClass().getClassLoader():获得代理对象的类加载器。
2.new Class<?>[]{Person.class}:获得目标类实现的接口。
前两个参数是为了获得一个包括类名、方法名、继承关系在内的躯壳。
3.proxy:它的类型为InvocationHandler , 它的目的就是一个有参数的构造器。
网友评论