关于java:从法外狂徒张三卖房引起的代理模式

37次阅读

共计 3671 个字符,预计需要花费 10 分钟才能阅读完成。

写在之前

谈到代理模式,最罕用的应用场景莫过于 AOP 中的利用了,在探讨 AOP 的实现之前,先来聊聊什么代理模式。

动静代理有两种模式,动态代理和动静代理,大家先不必在意两者的概念,等理解本篇你将会发现其实两者差异不大。

动态代理

用一个简略的例子来剖析什么是动态代理,用买房张三卖房这件事儿为例,聊聊代理模式有何作用,为何如此应用如此频繁。

Subject 接口:用于对 被访问者 的抽象化(比方卖房这件事儿)

SubjectImpl:被访问者的具体实现(张三想要卖房)

SubjectProxy:被访问者的代理实现类,该类须要有一个 Subject 接口具体的实例。(比方房产中介,须要拿着张三受权才能够代理)

Client:访问者的形象。(比方李四想买房,自身是一个顾客)

代理类自身就是替被访问者做事的,李四想买房子,提了很多要求,比方朝南、学区房;房产中介(SubjectProxy)看张三家的房子刚好合乎李四预期,将张三的房子介绍给李四;相当于当一个中间人的意思。有人可能会说,就相似于一个介绍的活儿吗?非得让中介来吗?如果只是简略的介绍,还真不须要中介,然而中介能够帮忙跑贷款、帮忙把握合同等。

这样,张三只须要受权给中介,就能够一边做别的事儿,一边更加省心地实现交易。

下面的图牵强附会变成了如下的模式

被代理的形象接口——房子

public interface House {
    /**
     * 卖房子
     */
    void sell();}

被拜访的类——张三的房子

public class HouseForZhangsan implements House {


    @Override
    public void sell() {System.out.println("zhangsan sell house…………");
    }
}

代理类——房产中介

public class HouseProxy implements House {

    private House house;

    // 通过构造方法做到每次替不同的人代理
    public HouseProxy (House house) {this.house = house;}
    @Override
    public void sell() {house = new HouseForZhangsan();
        house.sell();}
}

测试类——交易场合

public class Test {public static void main(String[] args) {
        // 结构具体的卖房者
        House house = new HouseForZhangsan();
        // 将张三交给中介代理
        House houseForPerson = new HouseProxy(house);
        houseForPerson.sell();}
}

还是回到 Spring AOP 模式中,其中 SubjectProxy 就像是 SubjectImpl 的中介,而 SubjectImpl 自身是零碎中的 JoinPoint 所在的对象(指标对象),牵强附会地为指标对象创立一个代理对象,实现切面的逻辑。

然而各位想想,市面上并不是只有房子卖呢,张三家里有一辆闲暇的车,也想卖,还能去找房产中介吗?

必定不能了。

于是催生出了专门用于车交易的中介,比方瓜子二手车(号称没有中间商赚差价,哈哈哈)、二手车之家等等。

<img src=”https://cdn.jsdelivr.net/gh/kaoyan-guide/personPic@main/imgBlog/spring/20210417205209.png” alt=” 二手车平台 ” style=”zoom:50%;” />

再比方万一张三忽然发现手机用久了,想卖掉二手手机,新的 iPhone,于是又呈现了各种各样的二手手机平台(其实实质也是一种中介)

<img src=”https://cdn.jsdelivr.net/gh/kaoyan-guide/personPic@main/imgBlog/spring/20210417205454.png” alt=” 二手手机 ” style=”zoom:40%;” />

……

……

等等,那有人可能会想,能不能搞一个中介,可能啥都卖呢?于是更加全面的二手平台应运而生了。

在这下面能够灵便的代理各种商品 (被代理对象),这就达到了一种 动静中介的成果

对,没错,动静代理 曾经介绍完了。

<img src=”https://cdn.jsdelivr.net/gh/kaoyan-guide/personPic@main/imgBlog/spring/20210417210047.png” alt=”image-20210417210040941″ style=”zoom:50%;” />

开玩笑,持续聊聊 Spring AOP 是如何利用动静代理的。

动静代理

能够指定接口在运行期间动静的生成代理对象。(换句话说:无论你要卖什么,你来的时候都能够给你找一个对应的中介)

那么如何动静生成代理类呢?

须要借助两个工具,一个是 java.lang.reflect.Proxy 类 和 java.lang.reflect.InvocationHandler,问题的关键在于如何实时的给客户产生一个满足要去的中介。

这个就是借助 InvocationHandler来动静生成代理类,还是以下面中介为例,咱们权且讲要生成的代理类叫做 target.

如何动静产生不同类型的中介?

第一步必定须要晓得此时替什么类型客户代理,然而又不能写得太死,咱们权且在生成代理类中先申明一个 被代理的对象。

第二步:通过某种形式将 被代理对象通过传入的形式传进来

第三步:将被代理对象与中介进行绑定。

/**
 * 被代理的指标
 */
public Object target;

/**
 * 绑定委托对象,并且生成代理类
 * @param target
 * @return
 */
public Object bind(Object target) {
    this.target = target;
    // 绑定该类实现的所有接口,获得代理类
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                                  target.getClass().getInterfaces(), this);
}   

上述几步部署实现之后,会明确中介要替什么人做事儿,中介做什么事儿,并且将中介与客户关联起来。

最初才是真正的替客户做事儿。

public class SellInvocationHandler implements InvocationHandler {

    /**
     * 被代理的指标
     */
    public Object target;

    /**
     * 绑定委托对象,并且生成代理类
     * @param target
     * @return
     */
    public Object bind(Object target) {
        this.target = target;
        // 绑定该类实现的所有接口,获得代理类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                                      target.getClass().getInterfaces(), this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {log.info("额定逻辑……");
        return method.invoke(target, args);
    }
}

还记得咱们之前说过的吗?

动静代理解决的只是灵便产生不同代理类(换句话说灵便搭配不同类型中介)

至于做什么类型事儿,和替什么人做什么事儿这两件事儿还是得存在。

因而依然须要申明 两个类

做什么类型事儿

public interface House {
    /**
     * 卖房子
     */
    void sell();}

替什么人做什么事儿

public class HouseForZhangsan implements House {
    @Override
    public void sell() {System.out.println("zhangsan sell house…………");
    }
}

而后就能够欢快地进行交易了,每次有新的顾客来,就能够叫不同类型的中介来服务。

public class DynamicProxyTest {public static void main(String[] args) {SellInvocationHandler invocationHandler = new SellInvocationHandler();

        // 将被拜访类和代理类互相绑定(将房产中介 与 房子卖者互相绑定)House house = (House) invocationHandler.bind(new HouseForZhangsan());
        
        // 真正执行
        house.sell();}
}

至此,咱们曾经实现了真正的灵便代理工作。

动静代理虽好,却不能解决所有的事件。比方,动静代理只能对实现了相应接口 (Interface) 的类应用,如果某个类没有实现任何的 Interface,就无奈应用动静代理机制为其生成相应的动静代理对象。

正文完
 0