代理模式可分为静态代理,动态代理。
1.静态代理:
静态代理的角色分析:
- 真实对象;
- 代理真实对象的对象(代理对象)一般会添加一些附加的操作;
- 真实对象和代理对象抽象出来的公共部分(一般为抽象类或者接口);
- 用户(通过代理对象来调用真实对象的方法)。
静态代理的一个代码案例:
情景模型:你(用户)通过租房中介(代理对象)从房东(真实对象)进行租房的活动。
真实对象(Host)
//真实对象
public class Host implements Rent {
public void rent() {
System.out.println("Host 租房子啦!");
}
}
代理对象
//代理对象
public class Proxy implements Rent {
private Host host;
public Proxy(Host host) {
this.host = host;
}
public void rent() {
lookHouse();
host.rent();
fare();
}
//代理对象添加的额外的操作
public void lookHouse(){
System.out.println("带你一起去看看房子!");
}
public void fare(){
System.out.println("交易结束,请按时付款!");
}
}
抽象接口:
//抽象接口
public interface Rent {
void rent();
}
测试类:
public class StaticProxy {
@Test
public void test(){
//通过代理对象执行真实对象的方法
Proxy proxy = new Proxy(new Host());
proxy.rent();
}
}
总结:
真实对象,代理对象都实现了接口(房东,中介都来完成租房子这个活动),用户最后通过中介完成和房东的交易,其中还包含了自己额外的一些操作。
优点:
-
可以使真实角色更加纯粹,不用去关注一些公共的事情;
-
公共的业务由代理来完成,实现业务的分工;
-
公共业务的要扩展的话,可以更加集中和方便;
缺点:
假如我们的真实角色变得非常多,代理类也会随之增多,工作量变大,开发效率变低!
2.动态代理:
动态代理和静态代理中的角色都是一样的,差别在于:静态代理中代理类是直接写好的(代理类也是实现了接口),而动态代理中代理类是动态生成的。(代理对象的动态生成)
动态代理的实现可分为两类:
基于接口的实现JDK;
基于类:cglib(Code Generation Library);
(本文中探究基于jdk接口的实现)
(1).首先研究一个接口 一个类:
InvocationHandler:是一个接口,重写 invoke()方法。
是由代理实例的调用处理程序实现的接口 。每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
invoke(Object proxy, 方法 method, Object[] args)
处理代理实例上的方法调用并返回结果。
(该invoke方法是实现invocationHandler接口时,要写的方法,proxy:真实对象 method:真实对象中定义的方法 args 方法参数)
Proxy: 是一个类。
提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类.
方法: newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
(这个Proxy的静态方法,可以返回一个代理实例(抽象接口的实例),loader:当前对象的类加载器(this)interfaces:代理类实现的接口 h:this)
(2).动态代理的一个实例:
接口:
//接口
public interface Rent {
void rent();
}
真实对象:
//真实对象
public class Host implements Rent {
public void rent() {
System.out.println("Host租房la~");
}
}
动态代理动态的生成代理对象:
//动态代理对象,可以动态的生成一个代理类
public class DynamicProxy implements InvocationHandler {
//代理的是一个接口
private Rent rent;
public DynamicProxy(Rent rent) {
this.rent = rent;
}
//获得代理对象
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
//重写的invoke方法,用户进行调用后,就执行这个方法
//就相当于代理类中重写的接口的方法
//参数解析: o:代理对象(属性 接口)
// method:就是接口中原来定义的方法
// objects:method方法的参数
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
look(); //附加的额外操作
method.invoke(rent,objects); //调用的是真实对象中定义的方法
fare(); //附加的额外操作
return null; } //一些附加操作
public void look(){
System.out.println("我们不是黑中介");
}
public void fare(){
System.out.println("请交出服务费~");
}
}
测试类:
public class DynamicProxyTest {
@Test
public void test(){
Rent rent =new Host(); //真实对象
DynamicProxy proxy = new DynamicProxy(rent); //构造方法
Rent proxy1 =(Rent) proxy.getProxy(); //获得代理对象
proxy1.rent(); //调用代理对象的方法
}
}
(3).总结:
动态代理和静态代理最大区别就是可以在程序中动态的生成代理对象,使用到了Invocation接口(重写invoke方法),和Proxy(创建代理对象)使用 newProxyInstance(classLoader, interface, object)方法获得代理对象的实例。