静态代理
静态代理角色分析
- 抽象角色:一般使用接口或者抽象类来实现
- 真实角色:被代理的角色
- 代理角色:代理真实角色;代理真实角色后,一般会做一些附属的操作。
- 客户:使用代理角色来进行一些操作
代码实现
抽象角色:租房
public interface Rent{
public void rent();
}
真实角色:房东,房东要出租房子
public class Host implements Rent{
public void rent(){
System.out.println("房屋出租");
}
}
代理角色:中介
public class Proxy implements Rent{
private Host host;
public Proxy(){}
public Proxy(){
this.host = host;
}
//租房
public void rent(){
seeHose();
host.rent();
fare();
}
//看房
public void seeHose(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
客户:租房子的人
public class Client{
public static void main(String[] args){
//房东要租房
Host host = new Host();
//中介帮助房东
Proxy proxy = new Proxy(host);
//客户去找中介
proxy.rent();
}
}
静态代理的好处:
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- 公共的业务由代理来完成 . 实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
缺点 :
- 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .
动态代理
动态代理分为两类:一类是基于接口的动态代理,一类是基于类的动态代理
基于接口的动态代理:JDK动态代理
基于类的动态代理:cglib
JDK动态代理
需要使用InvokeHandler接口和Proxy类。
InvokeHandler:调用处理程序
Object invoke(Object proxy, 方法 method,Object[] args)throws Throwable
参数:
proxy - 调用该方法的代理实例
method - 所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
Proxy:代理
Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
Proxy中存在一个静态方法newProxyInstance可以返回指定接口的代理类的实例。
public static Object newProxyInstance(ClassLoader loader,类<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException
参数 :
loader - 类加载器来定义代理类
interfaces - 代理类实现的接口列表
h - 调度方法调用的调用处理函数
代码实现:
抽象角色:租房
public interface Rent{
public void rent();
}
真实角色:房东,房东要出租房子
public class Host implements Rent{
public void rent(){
System.out.println("房屋出租");
}
}
代理角色
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 : 代理类的调用处理程序的方法对象.
// 处理代理实例上的方法调用并返回结果
@Override
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("收中介费");
}
}
客户:租房子的人
public class Client{
public static void main(String [] args){
//真实角色
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(Host);//将真实角色放置进去!
Rent proxy = (Rent)pih.getProxy();//动态生成对应的代理类!
proxy.rent();
}
}
动态代理的优势(与静态代理相比)
静态代理可以在不改变原代码的前提下对程序进行增强,但是每次进行代理的时候都要写一个类,代码非常的麻烦,但是动态代理通过反射的方式获取被代理类的相关参数,代理的是一个接口,只要是实现了该接口的类,用同一段代码都能实现代理,少写了很多的代理类。