代理模式(静态代理、jdk动态代理)

1.代理模式的定义:

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。


2.组成的角色:
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。


3.代理模式的好处:

(1).职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
(2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介解耦的作用和保护了目标对象的作用,并可以附加自己的操作。
(3).高扩展性


4.通过小例子理解代理模式:

public abstract class AbstractTarget {

    public abstract void dosomething();
}
public class ConcreteTarget extends AbstractTarget {
    @Override
    public void dosomething() {
        System.out.println("go home");
    }
}
public class MyProxy extends AbstractTarget {
    //静态代理
    //编译期就已经明确指定了真实需要代理的类就是ConcreteTarget
    private AbstractTarget target = new ConcreteTarget();

    @Override
    public void dosomething() {
        target.dosomething();
    }
}
public static void main(String[] args) {
    AbstractTarget target = new MyProxy();
    target.dosomething();
}
执行结果:

go home


这是一个最简单到代理模式的例子,客户端使用代理的dosomething()方法时,代理类委托给了真实角色ConcreteTarget执行,这就是代理模式。代理类成为客户端与真实角色直接的桥梁,在不同的场景下,这个桥梁可以起到很大的现实作用,这个在本文后面再讲述。

可以看到,该例中由于编译期已经知道代理的真实角色是谁了,所以这种代理模式又叫做静态代理

//静态代理
//编译期就已经明确指定了真实需要代理的类就是ConcreteTarget
private AbstractTarget target = new ConcreteTarget();

5.jdk动态代理

相对静态代理而言,动态代理是值编译器不知道代理的真实角色是谁,需要在运行期才能确定。


我们有一个超级明星的接口。

public interface SuperStar {

    void call();

    void sing();

    void dance();
}

有一个歌手实现了超级明星的接口。

public class Singer implements SuperStar {

    @Override
    public void call() {
        System.out.println("我正在休息,不要打扰我");
    }

    @Override
    public void sing() {
        System.out.println("唱歌我在行,让我来");
    }

    @Override
    public void dance() {
        System.out.println("跳舞找dancer");
    }
}
但是明星都很忙的,还要耍耍大牌,所以需要一个经纪人作为他的代理人,处理对外事宜。可是现在是用的jdk动态代理了,与先前的例子写法完全不一样了。jdk API中有个InvocationHandler调用处理器的接口。我们需要先定义一个自己的调用处理器。

public class BrokerInvocationHandler implements InvocationHandler {

    private SuperStar superStar;

    public BrokerInvocationHandler(SuperStar superStar){
        this.superStar = superStar;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("sing")){
            method.invoke(superStar,args);
            System.out.println("歌手同意了,我们准备准备就来");
            return null;
        }else if (method.getName().equals("dance")){
            System.out.println("跳舞别来找我们");
            return null;
        }else if (method.getName().equals("call")){
            System.out.println("人不在,有什么事找我好了");
            return null;
        }else {
            return null;
        }
    }
}
public class BrokerProxy {

    public static SuperStar newProxyInstance(SuperStar superStar){
        return (SuperStar) Proxy.newProxyInstance(superStar.getClass().getClassLoader(),
                superStar.getClass().getInterfaces(),new BrokerInvocationHandler(superStar) );
    }
}
有了这2个类,代理就算完成了。

public class Test {

    public static void main(String[] args) {
        SuperStar singer = BrokerProxy.newProxyInstance(new Singer());
        singer.sing();
        singer.call();
        singer.dance();
	//true:说明singer的父类就是Proxy
System.out.println(singer.getClass().getSuperclass() == Proxy.class); }}

运行结果:

唱歌我在行,让我来
歌手同意了,我们准备准备就来
人不在,有什么事找我好了
跳舞别来找我们
true


jdk动态代理总结:
     
      1.定义自己的InvocationHandler实现类BrokerInvocationHandler
     
      2.通过Proxy类的newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法创建动态代理类
     
      3.通过反射获取动态代理类的构造函数,并通过该构造函数创建代理类实例singer
     
      4.被创建出来的实例singer继承了Proxy类(因此java动态代理只能代理接口,这是由java不支持多继承的设计决定的),实现了目标接口SuperStar
     
      5.调用singer的任意方法,实际上都会先调用到BrokerInvocationHandler中的invoke方法,然后通过反射调用Method的invode方法调用实际被代理的方法
     
      6.调用到BrokerInvocationHandler中的invoke方法时,可以获得被代理方法的信息,因此可以在真正调用invoke方法前、后写上自己的业务逻辑


5.代理模式的变形

在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用 Proxy模式。下面是一些可以使用Proxy模式常见情况:
1) 远程代理(Remote  Proxy)为一个位于不同的地址空间的对象提供一个本地的代理对象。这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)


2) 虚拟代理(Virtual Proxy)根据需要创建开销很大的对象。如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。 


3) 保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。


4) 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。


5) Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。

6)缓存代理(Cache Proxy)


7)防火墙代理(Application Gateway


8)同步代理

等等。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值