代理模式
为什么要学习代理模式?
因为他就是SpringAOP的底层!【SpringAOP和SpringMVC时面试必问!】
代理模式的分类:
- 静态代理
- 动态代理
1.静态代理
角色分析:
- 抽象角色:一般使用接口或者抽象类来实现
- 真实角色:被代理人
- 代理角色:代理真实角色
- 客户:访问代理对象的人
代码步骤:
- 接口
public interface Rent { public void rent(); }
- 真实角色(房东)
//房东 public class Host implements Rent{ @Override public void rent() { System.out.println("房东出租房子"); } }
- 代理角色(中介)
public class Proxy implements Rent{ //多用组合,少用继承 private Host host; public Proxy(Host host) { this.host = host; } public Proxy() { } @Override public void rent() { host.rent(); System.out.println("代理已经帮房东租房子了"); } //看房 public void seeHouse(){ System.out.println("代理带你看房"); } //收中介费 public void fare(){ System.out.println("代理收中介费"); } //签合同 public void hetong(){ System.out.println("代理签租赁合同"); } }
- 客户
public class Client { public static void main(String[] args) { Proxy proxy = new Proxy(new Host()); //代理,中介帮房东租房子,代理角色会有附加操作,比如收中介费,签合同 //不用面对房东直接找中介租房子 proxy.seeHouse(); proxy.hetong(); proxy.fare(); proxy.rent(); } }
代理模式的好处:
- 可以使真实角色的操作更加纯粹
-
公共业务交给代理角色,实现业务分工
-
公共业务发生扩展的时候方便集中管理
代理模式的缺点:
- 一个真实角色就会产生一个代理角色
- 代码量翻倍,开发效率变低
2. 动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口:JDK动态代理【在这里我们先使用这个】
- 基于类:cglib
- 现在较为流行:java字节码(javassist)
首先需要了解两个类:Proxy(代理),invocationHandler(调用处理程序)
第一个类Proxy是用来生成得到的代理类
第二个类是我们的核心,这是一个接口,我们需要实现它内部的一个方法invoke,这个invoke方法其实就是java反射里面我们用来激活method的invoke方法。
//我们用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(Host.class.getClassLoader(),Host.class.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(rent, args);
return invoke;
}
}
我们用实现了InvocationHandler接口的类来生成代理类
newProxyInstance(Host.class.getClassLoader(),Host.class.getInterfaces(),this)
参数1:真实对象的类加载器,用来寻找
参数2:说明你要生成的代理类的接口。
参数3:实现了InvocationHandle的类,这个类只有一个方法需要你要实现它。
invoke(Object proxy, Method method, Object[] args)
这个方法第一个参数,是生成的代理类,目前没发现用处,不管它。
第二个参数,是执行的方法(利用反射获得真实角色的方法对象,再利用invoke激活这个方法)
第三个参数,是执行某方法需要的参数。
注意:在代理对象调用接口中方法的时候,就会调用这个invoke方法
- 接口:
public interface Rent {
public void rent();
}
- 真实角色
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
- 用户:
public class Client {
public static void main(String[] args) {
ProxyInvocationHandler handler = new ProxyInvocationHandler();
Host host = new Host();
handler.setRent(host);
Rent proxy = (Rent) handler.getProxy();
proxy.rent();
}
}
总结:InvocationHandler接口是核心实现类,用来帮助我们实现真实角色的方法,我们利用多态的性质将真实角色set给InvocationHandler,Proxy的newProxyInstance方法用来生成代理类
这个方法第一个参数,是生成的代理类,目前没发现用处,不管它。
第二个参数,是执行的方法(利用反射的原理,可以去看反射,也很简单。)
第三个参数,是执行某方法需要的参数。
Comments | NOTHING