从狡猾的房产中介来看动态代理



探索Android软键盘的疑难杂症
深入探讨Android异步精髓Handler
详解Android主流框架不可或缺的基石
站在源码的肩膀上全解Scroller工作机制



Android多分辨率适配框架(1)— 核心基础
Android多分辨率适配框架(2)— 原理剖析
Android多分辨率适配框架(3)— 使用指南



自定义View系列教程00–推翻自己和过往,重学自定义View
自定义View系列教程01–常用工具介绍
自定义View系列教程02–onMeasure源码详尽分析
自定义View系列教程03–onLayout源码详尽分析
自定义View系列教程04–Draw源码分析及其实践
自定义View系列教程05–示例分析
自定义View系列教程06–详解View的Touch事件处理
自定义View系列教程07–详解ViewGroup分发Touch事件
自定义View系列教程08–滑动冲突的产生及其处理


版权声明


代理模式简介

代理模式(Proxy Pattern)是面向对象中一种非常常见的设计模式。其实,不单是在软件开发领域,在我们的日常生活中对于代理也时常可见。比如:房东要将自家的房租出售,于是到房地产中介公司找一个代理,由他来帮自己完成销售房屋,签订合同等等事宜。

在此,就以该生活场景为蓝本介绍Java的代理模式。一般而言,代理技术可分为:静态代理和动态代理;我们先来看静态代理。


静态代理示例

房东通过一纸协议将自己的房子挂靠在房屋中介公司,委托中介出售其房屋。嗯哼,我们来一起瞅瞅这个房东和中介公司共同达成的协议:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public interface TradeProtocol {
    public void sellHouse(int money);
}

嗯哼,这个协议很简单,房东委托中介公司售卖自己的房子。

既然是房东和房屋中介共同达成的协议,那么房东和中介都需要遵守该协议。

先来看房东:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public class Owner implements TradeProtocol{

    @Override
    public void sellHouse(int money) {
        System.out.println("我是房主,我的房子卖了"+money+"块钱");
    }

}

再来看中介:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public class HouseAgent implements TradeProtocol {
    private TradeProtocol mHouseProtocol;

    public HouseAgent(TradeProtocol houseProtocol){
        mHouseProtocol=houseProtocol;
    }
    @Override
    public void sellHouse(int money) {
        System.out.println("我是中介,业主的房子卖了"+money+"块钱");
        mHouseProtocol.sellHouse(money);
    }

}

请注意HouseAgent的实现

  • 在HouseAgent的构造方法中传入TradeProtocol的对象,比如Owner
  • 在HouseAgent的sellHouse()中调用TradeProtocol的对象(比如Owner)的sellHouse()
  • 所以,HouseAgent售卖(sellHouse())房子,实际上是房东自己售卖了房屋!

测试如下:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public class Test {

    public static void main(String[] args) {
        Owner owner=new Owner();
        HouseAgent houseAgent=new HouseAgent(owner);
        houseAgent.sellHouse(10000*100);
    }

}

测试结果:

我是中介,业主的房子卖了1000000块钱
我是房主, 我的房子卖了 1000000块钱

在该静态代理中,房东将房屋的售卖交给了中介代理,中介将房屋出售后又把钱一分不少地交给了房东。咦,这咋不对呢?现实中有这样大公无私,视金钱如粪土的房屋中介么?没有!绝对没有!万一,你发现有类似的情况,请举起自己的双手抽自己两耳光:醒醒,别睡了,别做白日梦了!

那么,中介是怎么赚钱的呢?我们继续往下看


动态代理示例

与之前一样,房东和房屋中介公司之间存有一纸协议:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public interface TradeProtocol {
    public void sellHouse(int money);
}

同样地,房东遵守该协议:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public class Owner implements TradeProtocol{

    @Override
    public void sellHouse(int money) {
        System.out.println("我是房主,中介告诉我:房子卖了"+money+"块钱");
    }

}

现在,房东又去房屋中介公司挂靠自己的房子,到了那一看:原来熟悉的那个中介出去办事了,刚好不在。正准备走呢,中介公司的经理挺着啤酒肚走过来,笑嘻嘻地说:请问您是来办理业务的吗?来,请坐,我给你们引荐以为我们这里服务最好的一个房屋中介人员办理您的相关事宜!

嗯哼,我们来看看这个这位被称为”服务最好的中介”是怎么卖掉房东的房子的:

package cn.com;

import java.lang.reflect.Proxy;

/**
 * 原创作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
public class TestProxy02 {

    public static void main(String[] args) {
        TradeProtocol owner=new Owner();
        ClassLoader classLoader=owner.getClass().getClassLoader();
        Class<?>[] interfaces = owner.getClass().getInterfaces();
        //创建InvocationHandler
        HouseAgentInvocationHandler invocationHandler=new HouseAgentInvocationHandler(owner);
        //生成动态代理
        TradeProtocol tradeProtocol=(TradeProtocol) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        tradeProtocol.sellHouse(1000000);
    }

}

HouseAgentInvocationHandler 的实现如下:

package cn.com;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 原创作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
public class HouseAgentInvocationHandler implements InvocationHandler {
    private Object object;

    public HouseAgentInvocationHandler(Object object) {
        this.object=object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Integer money=(Integer) args[0];
        System.out.println("我是中介,业主的房子我实际卖了"+money+"块钱");
        Object result=method.invoke(object, new Object[]{money/2});
        System.out.println("我是中介,这次交易我赚了不少钱!!!");
        return result;
    }
}

好了,所涉及到的代码就这么多。或许有一点看不懂,这也无妨,我们先看看运行的结果再作详细的解释。控制台输出信息如下:

我是中介,业主的房子我实际卖了1000000块钱
我是房主,我的房子卖了500000块钱
我是中介,这次交易我赚了不少钱!!!

哇哈,狡猾的中介把房子卖了100W却告诉房东只买了50W,自己狠狠地赚了一笔!这是怎么回事呢?不急,我们通过这两个示例来回顾一下卖房子的经过。

  • 第一个示例中,房东将房屋委托给一个自己熟知的中介人员售卖房产;中介卖了多少钱就给房东多少钱
  • 第二个示例中,房屋中介公司的经理临场(动态)地指定了一个中介人员为房东办理售卖房屋的相关事宜
  • 第二个示例中,中介对售卖的过程做了手脚。由此可见:动态代理可方便地对被代理类的方法进行某些处理。比如,在方法实际调用前做一些过滤或者拦截操作或者修改,在方法调用后做一些善后处理等。

好了,生活中的例子看完了,我们再回到工作中的代码,结合示例分析Java动态代理技术。


动态代理技术分析

在Java的动态代理机制中,有两个非常重要的不可或缺的东西:

  • InvocationHandler接口
  • Proxy类

先来瞅瞅InvocationHandler接口

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

这段官方文档的主要含义是:
每个动态代理类都必须要实现InvocationHandler接口,并且每个动态代理类的实例都关联到了一个handler。当我们通过代理调用被代理对象的方法时,该方法的调用会被转发至InvocationHandler接口的 invoke( )中进行处理,方法如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{}

该方法有三个输入参数,它们分别代表什么呢?

  • proxy:最终生成的代理
  • method:被代理对象正在执行的方法
  • args:被代理对象正在执行的方法的输入参数

这么说,或许有点摸不着头脑。没事,我们在HouseAgentInvocationHandler类的invoke( )方法开头加几句打印语句:

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy.getClass()="+proxy.getClass());
        System.out.println("method.getName()="+method.getName());
        for(Object object:args) {
            System.out.println("object.getClass()="+object.getClass());
        }
        ..............
    }

输出结果:

proxy.getClass()=class com.sun.proxy.$Proxy0
method.getName()=sellHouse
object.getClass()=class java.lang.Integer

嗯哼,看了InvocationHandler接口,再来瞅瞅Proxy类。

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

这段官方文档的主要含义是:
Proxy用于动态创建一个代理类及其实例。该类中我们常用 newProxyInstance( )方法:

 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler)  throws IllegalArgumentException {}

该方法有三个输入参数,它们分别代表什么呢?

  • loader:加载动态代理类的ClassLoader,该输入参数通常为被代理类的类加载器
  • interfaces:动态代理类需要实现的接口,该输入参数通常为被代理类使用的接口
  • handler:动态代理对象在调用方法时与之关联的InvocationHandler

从这里我们可以看出: 动态代理与静态代理的原理是一样的,但是在动态代理中它没有具体的代理类而是通过Proxy在JVM运行时利用反射动态地生成了一个代理。在静态代理中,需要代理(中介)与被代理对象(房东)遵守同一份协议;其实在动态代理中也是非常类似的,只不过它换了一种方式罢了,这点从newProxyInstance( )方法的参数interfaces就能看出端倪:这些接口(interface)不就是静态代理中的协议么?也可以这么理解:动态代理对于协议的遵守发生在newProxyInstance( )时;并且动态代理可以对原来协议中的方法”做手脚”!

至此,我们再回过头来梳理一下动态代理示例及其相关技术:

  • 房东遵守房屋售卖协议
  • 动态地生成代理,在生成代理的过程中代理也遵守了房屋售卖协议
  • 代理在执行协议中的方法时(比如sellHouse( )),将该方法转发至与该代理密切相关的InvocationHandler中
  • 在InvocationHandler中可对协议中的方法(比如sellHouse( ))进行额外的附加的处理
  • 在InvocationHandler中利用反射调用协议中的方法(比如sellHouse( ))。其实,从这里也可以看出来:动态代理属于Java反射技术范畴;或许细心的人从导包语句中也有所发现:java.lang.reflect.InvocationHandler;嗯哼,InvocationHandler就在reflect包下

小感悟

很多刚开始做开发的童鞋喜欢拿着一本厚厚的设计模式在角落里默默地啃。学习的劲头很足,态度也很端正,配得上10086个赞。在此,我也想提醒一下小伙伴们:学习态度和努力程度固然非常重要,但是我们也要注意学习方法。抛开实际应用和业务逻辑单纯地看设计模式是很难理解其精髓的。我们不妨将设计模式和自己的实际工作结合起来学习,比如做Android开发的小伙伴可结合Android源码或者非常流行的第三方库来深入地研究设计模式,在此推荐一篇《Retrofit分析-漂亮的解耦套路》供大家学习参考


参考资料

时间: 2024-09-20 01:09:35

从狡猾的房产中介来看动态代理的相关文章

后台(29)——动态代理

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Android多分辨率适配框架(3)- 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View

电商与线下龙头房产中介“联姻”

李宇嘉 站在全产业链的角度来看,搜房网与世联行和合富辉煌的业务具有相当强的互补性,其结合也必将给未来房产中介服务领域.存量时代房产业务带来革命性的变革. 搜房网之所以紧锣密鼓地与线下龙头房产中介"联姻",盖因年初中介集体围剿电商平台.最终,搜房网因其对传统中介的依赖而妥协.近几年,互联网公司把传统商业模式冲击的七零八落,但在房产中介领域却无能为力.搜房网尽管贵为全球最大的房地产家居网络平台,但其集聚的海量用户和客户黏度如果要转化成现实的利润,必须要依赖于传统中介线下的业务. 一个很简单

房产中介以电商思维切入团购营销,与房企捆绑抱团过冬

摘要: 在房产市场粗放发展的时代,无论采用什么样的营销方式,房企都能轻松赚到钱.然而,现在这场躺着赚钱的游戏已经结束,随着第三方网络平台的崛起,房产中介以电商思维切入团购 在房产市场粗放发展的时代,无论采用什么样的营销方式,房企都能轻松赚到钱.然而,现在这场"躺着"赚钱的游戏已经结束,随着第三方网络平台的崛起,房产中介以电商思维切入团购营销,与房企捆绑抱团过冬.但今年以来,房产中介与网络平台之间突然反目成仇,双方斗得难分输赢. <每日经济新闻>记者注意到,随着微信营销的崛起

java之架构基础-动态代理&amp;amp;cglib

本文核心主要参数动态代理和cglib: 在以前的文章中,有提及到动态代理,它要解决的就是,当我们的某些代码前面或后面都需要一些处理的时候,如写日志.事务控制.做agent.自动化代码跟踪等,此时会给你带来无限的方便,这是JVM级别的提供的一种代理机制,不过在这种机制下调用方法在JVM7出来前还没有invokeDynamic的时候,调用的效率是很低的,此时方法调用都是通过method的invoke去实现. 其基本原理是基于实现JVM提供的一个: InvocationHandler的接口,实现一个方

使用JAVA中的动态代理实现数据库连接池

动态|数据|数据库|数据库连接 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的连接数据库对服务性能来讲是一个瓶颈,使用缓冲池技术可以来消除这个瓶颈.我们可以在互联网上找到很多关于数据库连接池的源程序,但是都发现这样一个共同的问题:这些连接池的实现方法都不同程度地增加了与使用者之间的耦合度.很多的连接池都要求用户通过其规定的方法获取数据库的连接,这一点我们可以理解,毕竟目前所有的应用服务器取数据库连接的方式都是这种方式实现的.但是另外一个共同的问题是,它们同时不允许使用者显式的调用Co

spring入门(13) JDK动态代理

首先我们来了解一下java中的代理模式,代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就 是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象 ,而代理对象可以在客户端和目标对象之间起到中介的作用. 1.抽象主题角色 声明了真实主题和代理主题 的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题 2.代理主题(Proxy)角色: 代理主题角色内部含有对真实主题的引用,从而可以在任

Android插件化原理解析——Hook机制之动态代理

转发必注明出处:Hook机制之动态代理 使用代理机制进行API Hook进而达到方法增强是框架的常用手段,比如J2EE框架Spring通过动态代理优雅地实现了AOP编程,极大地提升了Web开发效率:同样,插件框架也广泛使用了代理机制来增强系统API从而达到插件化的目的.本文将带你了解基于动态代理的Hook机制. 阅读本文之前,可以先clone一份 understand-plugin-framework,参考此项目的dynamic-proxy-hook模块.另外,插件框架原理解析系列文章见索引.

动态代理方式实现AOP

摘要:面向对象的思想强调"一切皆是对象",在面向对象的程序中我们使用真实概念的模型思考问题,使得整个软件系统开发可以像搭建房屋一样有条不紊.然而面向对象也并非完美无缺的,它更注重于对象层次结构方面的东西,对于如何更好的管理对象行为内部结构,还存在着些许不足.那么我们如何使这个问题的得到更完美的解决呢?答案就是AOP. 主要内容: AOP简述 利用动态代理实现AOP 总结 一.AOP简述 AOP的概念早在上个世纪九十年代初就已经出现了,当时的研究人员通过对面向对象思想局限性的分析研究出了

java学习笔记13--反射机制与动态代理

Java的反射机制 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的. 这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制. Java 反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类. 在运行时构造任意一个类的对象. 在运行时判断任意一个类所具有的成员变量和方法. 在运行时调用任意一个对象的方法 Reflection 是Java被视为动态(或准动态)