代理模式的作用:为其他对象提供一种代理以控制对这个对象的访问
代理模式一般涉及到的角色有:
1.抽象角色:声明真实对象和代理对象的共同接口
2.代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
3.真实角色:代理角色所代表的真实对象,是我们最终要引用的对象
代理模式又分为静态代理与动态代理
就比如以现实生活中买房子为例,买家为真实需求的目标对象,中介就是代理对象
RealBuyer.java
public class RealBuyer { public void buyHouse(String name, int price) { String ss = "buy name:"+name+" , price: "+price; System.out.println(ss); } }
ProxyBuyer.java
public class ProxyBuyer { private RealBuyer realBuyer; public ProxyBuyer(RealBuyer rb){ this.realBuyer = rb; } public void buyHouse(String name, int price) { this.beforBuy(); realBuyer.buyHouse(name, price); this.afterBuy(); } public static void beforBuy(){ System.out.println("do sth. before"); } public static void afterBuy(){ System.out.println("do sth. after"); } }客户端调用:
Client.java
public class Client { public static void main(String[] args) { ProxyBuyer proxyBuyer = new ProxyBuyer(new RealBuyer()); proxyBuyer.buyHouse("Beijing", 10); } }结果为
do sth. before buy name:Beijing , price: 10 do sth. after以上就是java的静态代理模式,可以发现其中的问题,一种代理类只能代理一种对象,只能代理一个方法,产生很多冗余的代码,实际情况中中介也会代理卖房子,代理多个买房卖房的客户,所以这样做很麻烦。其实JDK还提供了动态代理模式,其核心就是一个接口类InvocationHandler与一个Proxy类,上面的问题可以这么做
可以先把需要解决的问题抽象一个接口
Buyer.java
public interface Buy { public void buyHouse(String name,int price); }接下来只让实际的买家(真实对象)去实现这个方法,中介这不需要
RealBuyer.java
public class RealBuyer implements Buy{ @Override public void buyHouse(String name, int price) { System.out.println("RealBuyer: This is "+name+",price : "+price); } }
DynamicProxyBuer .java
public class DynamicProxyBuer implements InvocationHandler { private Object target; public DynamicProxyBuer(Object obj){ this.target = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("do ... before"); Object object = method.invoke(target, args); System.out.println("do .. after"); return object; } }代理对象实现了一个InvocationHandler接口
实际调用操作的时候
Cilent.java
import java.lang.reflect.Proxy; public class Cilent { public static void main(String[] args) { DynamicProxyBuer dynamicProxyBuer = new DynamicProxyBuer(new RealBuyer()); Buy buy = (Buy)Proxy.newProxyInstance(TestDynamic.class.getClassLoader(), new RealBuyer().getClass().getInterfaces(), dynamicProxyBuer); buy.buyHouse("NanJing", 300); } }结果:
do ... before RealBuyer: This is NanJing,price : 300 do .. after
代理类实现InvocationHandler接口,重写了invoke方法,invoke第一个参数是代理对象,第二个是代理对象的某个方法,第三个参数是该方法的参数,支持可变参数的形式传入
Proxy类中有个静态方法newProxyInstance,第一个参数是一个类加载器,第二个是被代理对象实现的接口,第三个参数是InvocationHandler对象的一个实例,返回一个Object的代理对象,其实就是实现了真实对象接口的代理,所以可以强制转换以便调用方法
这样一来,就可以让我们的动态代理类代理任何对象的任何方法。如果不想让其代理某个对象的某个方法只需要在动态代理类的invoke方法中获得Method名,过滤之即可