目录
- 什么是代理?
- 什么是静态代理?
- 什么是动态代理?
- 什么是Proxy?
- 什么是InvocationHandler?
1. 什么是代理
生活中的代理:租客因为一些原因(找不到房源、怕被坑等)需要中介来帮助他来租房。在租房的过程中,可以借助中介来干一些其他的事情(砍价,拟合同…)
程序中的代理:当前类因为一些原因(无法修改导入包的代码等)需要 代理类 来帮助自己执行方法。在执行的过程中,可以让 代理类 来干一些其他事情(输入,修改值…)
2. 什么是静态代理
代理类需要自己去创建,编写代码。
不多说废话,直接上代码
/**
* 租房接口
*/
public interface Rent {
void rentHourse();
}
/**
* 代理类,中介
*/
public class Mediation implement Rent {
@Override
public void rentHourse() {
// 在租房之前进行砍价
System.out.println("租房");
// 在租房之后进行合同保管
}
}
/**
* 租户
*/
public class Tenant {
public void rent() {
// 让中介代理租房子
new Mediation().rentHourse();
}
}
当项目中目标类和代理类很多的时候,会有以下的问题:
(1)当目标类增加了,代理类可能也需要成倍的增加,代理类数量过多。
(2)当你的接口中功能增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多。
因此,需要用到 动态代理类
3. 什么是动态代理
在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理目标类(静态代理中,代理目标是固定,写死的)。而不用创建代理类文件。
2. 什么是Proxy
Proxy 是代理类,一般使用 newProxyInstance() 方法来获取代理对象实例
说一下newProxyInstance()方法
/**
* 获取代理对象实例
* @param loader 用这个类加载器来加在对象实例
* @param interfaces 需要代理的真实对象所实现的所有接口组成的数组,这样代理对象就可以使用接口里的各个方法了
* @param h 该代理实例对应的 调用处理程序(对象实例)
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
3. 什么是InvocationHandler
首先,来看一下JDK文档里面的定义:
public interface InvocationHandler
InvocationHandler是一个由代理实例的 调用处理程序 实现的接口
每个代理实例都有一个关联的 调用处理程序。当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的 invoke 方法。
当看到这些名词的时候是不是有点懵?反正我第一次看到的时候是看不懂这个意思的。
首先,我们来看一下这些名词是什么意思:
- 代理实例
代理类的实例。比如,上面的导购员是一个类,只是一个职务,而职务是导购员的这个人,就是这个类的实例,即代理实例 - 调用处理程序
这是一个类,会关联着一个代理实例,需要实现InvocationHandler这个接口。作用就是,一使用代理对象实例的方法时,就会先转到它的invoke方法
下面来举一个例子,看看如何使用:
/**
* 工作接口
*/
public interface Work {
void work(String workName);
}
/**
* 人
*/
public class People implements Work{
@Override
public void work(String workName) {
System.out.println("workName=" + workName);
}
}
/**
* 调用处理程序
*/
public class WorkHandler implements InvocationHandler {
// 要代理的真实对象
People people;
// 传入一个真实类的实例,给该类真实对象复制
public void setPeople(People people) {
this.people = people;
}
/**
* @param proxy 代理对象
* @param method 我们需要调用的那个方法所对应的对象
* @param args 调用对象时的参数
* @return 需要代理的真实对象(也可以返回其他Object对象,比如 形参proxy)
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("在生成真实对象前做某些事");
Object invoke = method.invoke(people, args);
System.out.println("在生成真实对象后做某些事");
System.out.println(method.getName());
return invoke;
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
People people = new People();
WorkHandler workHandler = new WorkHandler();
// 设置需要代理的真正对象实例
workHandler.setPeople(people);
/**
* 通过Proxy类的newProxyInstance方法创建代理对象
* 第一个参数:people.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象
* 第二个参数:people.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法
* 第三个参数:handler,我们将代理对象关联到上面的InvocationHandler对象上
*/
Work proxy = (Work) Proxy.newProxyInstance(people.getClass().getClassLoader(),
people.getClass().getInterfaces(), workHandler);
proxy.work("唱跳rap篮球");
//System.out.println(proxy);
}
}
总结
- Proxy 是一个代理类,用来给真实对象创建代理实例的
- InvocationHandler 是 代理对象实例 对应的 调用处理程序 必须实现的接口。实现类该接口后,需要重写它的invoke方法。每次代理对象实例调用方法时,都会先执行该invoke方法。可以用于横向增加需要代理的真实对象的方法的功能(AOP)