什么是代理
代理是一种设计模式,提供了对目标对象另外的访问方式,即通过代理对象访问目标对象。可以不修改目标对象,对目标对象功能进行拓展。在我们学习Spring的时候就会发现,AOP(面向切面编程)的底层就是代理。
代理的实现可以分为静态代理和动态代理。动态代理又根据实现的方式分为:基于JDK接口的动态实现和基于Cglib类的动态实现
静态代理
这里可以通过一个现实中的具体例子,来理解代理:
- 抽象角色:一般会使用接口或者抽象类来解决,这里指代租房。
- 真实角色:被代理的角色,这里指代房东。
- 代理角色:代理真实角色,真实角色通过代理对象可以完成操作。这里指代中介。
- 客户:访问代理对象的人。这里指代租房的人
代码实现:
1,抽象角色(接口)
public interface Rent {
public void rent();
}
2,真实角色(房东)
public class Host implements Rent {
@Override
public void rent() {
System.out.println("我有房子要出租!!!");
}
}
代理角色(中介)
public class Proxy implements Rent {
private Host host;
public Proxy() {
}
//构造方法,和真实角色(房东)的连接
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
fare();
contract();
host.rent();
}
//看房
public void seeHouse() {
System.out.println("中介带你看房");
}
//收中介费
public void fare() {
System.out.println("收中介费");
}
//签合同
public void contract() {
System.out.println("签租赁合同");
}
}
4,客户(要租房的人)
public class Client {
public static void main(String[] args) {
//房东要租房子
Host host = new Host();
//代理,中介帮房东租房子,但是代理一般会有一些附属操作
Proxy proxy = new Proxy(host);
//你不用面对房东,直接面对中介
proxy.rent();
}
}
这里实现了房东出租房子给租客,但是租客完全和房东没有联系,完全靠中介来实现。那在租房子的过程中,遇到的附加操作也可以通过中间来实现。这就是静态代理的实现原理。
动态代理:(和静态代理角色一样 动态生成)
1,基于JDK接口的动态实现
首先我们需要学习两个类:Proxy :提供了创建动态代理类和实例的静态方法。InvocationHandler:invoke(proxy,method,):调用处理程序。下面附上官方的详细介绍:
InvocationHandler是java.lang.reflect包下的一个接口,其是由代理实例关联的调用处理程序实现的接口。因为每一个代理实例都会有一个关联的调用处理程序,所以当在代理实例上调用方法时,该方法将会被编码并分派到代理实例关联的调用处理程序的invoke方法中。(invoke是通过反射实现的)
实际操作进行代码实现:
1,抽象角色(接口)
public interface Rent {
public void rent();
}
2,真实角色(房东)
public class Host implements Rent {
@Override
public void rent() {
System.out.println("我有房子要出租!!!");
}
}
3,动态代理类(中介)
因为每一个代理实例都会关联一个调用处理程序,
因此我们的动态代理类要实InvocationHandler
接口。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//这个类的作用:自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理对象
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),
this);
}
//处理代理实例,并返回结果
//proxy:调用该方法的代理实例
//method:对应调用代理实例上的接口方法的实例
//args:包含方法调用传递代理实例的参数值的对象
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制
seeHouse();
Object result = method.invoke(rent, args);
fare();
return result;
}
public void seeHouse() {
System.out.println("中介带看房子");
}
public void fare() {
System.out.println("收中介费");
}
}
4.客户端
public class Client {
public static void main(String[] args) {
//真实角色(房东)
Host host = new Host();
//1,代理角色,现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//2,通过调用程序处理角色来处理我们要用的接口
pih.setRent(host);
//这里的Proxy就是利用我们写的动态代理类动态生成的
//3(动态代理类通过调用getProxy()方法生成代理对象,getProxy()方法中通过调用Proxy类的静态方法newProxyInstance生成代理类实例)
Rent proxy = (Rent)pih.getProxy();
//4
proxy.rent();
}
}
输出结果:
基于cglib类的动态实现
与JDK动态代理相比,基于cglib类的动态实现不需要接口,实现的具体流程也差不多,使用起来更简单。
动态代理的实现步骤:
首先,利用实现了InvocationHandler接口的生成一个动态代理角色。
第二,通过调用处理程序角色来处理我们要调用的接口对象。
第三,动态生成代理类实例。
最后,代理类实例处理对应的接口对象。
总结两者的区别:
1.代理分为静态代理和动态代理两种。
⒉.静态代理,代理类需要自己编写代码写成。
3.动态代理,代理类通过Proxy.newInstance()方法生成。
4.不管是静态代理还是动态代理,代理与被代理者都要实现两样接口 5.静态代理和动态代理的区别是在于要不要开发者自己定义Proxy类。
6.动态代理通过Proxy动态生成proxy class,但是它也指定了一个InvocationHandler的实现类。 7.代理模式本质上的目的是为了增强现有代码的功能。