博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
理解Java动态代理(1)—找我还钱?我出钱要你的命
阅读量:5849 次
发布时间:2019-06-19

本文共 5363 字,大约阅读时间需要 17 分钟。

代理模式是最常用的一个设计模式之一,理解起来也是很简单,一张图足以说明了,LZ就不废话了。

至于代理模式能干嘛也不是LZ今天想说的,今天主要想简单介绍下JAVA里面的动态代理。“动”当然是相对“静”来说的,那么什么是静,怎么就又动了呢?LZ想举个生活中常见的例子来说明,俗话说“谈钱伤感情”,但生活所迫LZ曾经可没少找人借个一百两百五的,话说借钱一时爽,还钱……(请自行造句),好点的心平气和的委婉的说,横点的就拳脚相加啊。我们来用接口表示下借钱者这个角色,他们可以采取peace或force的方式找我还钱:

/** * 借钱方 *  * @author moon *  */public interface ILender {    /**和平方式*/    public long peace(String name);    /**暴力方式*/    public long force(String name);}

我月中找张三借钱:

public class ZhangSanImpl implements ILender {    public long peace(String name) {        System.out.println("心平气和的找" + name + "要账。");        return 100;    }    public long force(String name) {        System.out.println("以暴力方式找" + name + "要账");        return 250;    }}

月底又找李四借钱(都是好欺负的货,动手干不过我):

public class LiSiImpl implements ILender {            public long peace(String name) {        System.out.println("心平气和的找" + name + "要账。");        return 100;    }    public long force(String name) {        System.out.println("以暴力方式找" + name + "要账");        return 250;    }}

张三和李四发现我老是借钱又拖帐,于是就合伙找了年级里一个比较横的角色(外号"JDK",由来是因为我叫jd,他是jd killer)来代他们要帐,好说不行就动手。看这就是代理模式。

/** * 借钱者的代理人 *  * @author jdzhan *  */public class CommonLenderProxy implements ILender {    /** 委托者 */    private ILender delegator;    public CommonLenderProxy(ILender delegator) {        this.delegator = delegator;    }    public long peace(String name) {        return delegator.peace(name);    }    public long force(String name) {        System.out.println("开始工作");        // 执行方法        long result = delegator.force(name);        System.out.println("搞定收工");        return result;    }}

于是乎我屈于淫威或者武力只能乖乖还钱鸟:

// Common Proxy CommonLenderProxy proxy = new CommonLenderProxy(new ZhangSanImpl()); long money = proxy.force("zhanjindong"); System.out.println("要回了" + money + "块QB");
开始工作以暴力方式找zhanjindong要账搞定收工要回了250块QB

 Ok,上面我用了亲身的一个小栗子说明了静态代理,那动态代理到底怎么实现,又有什么好处呢?我们先直接把上面的实现给出来。JDK动态代理中包含一个接口和一个类: 

InvocationHandler接口:

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

Proxy类:

public static Object newProxyInstance(ClassLoader loader, Class
[] interfaces, InvocationHandler h) throws IllegalArgumentException

"JDK"觉得代人要钱很有钱途,于是搞了个“帮会”:

/** * “JDK”代人人要账帮会 *  * @author jdzhan *  */public class DynamicLenderProxy implements InvocationHandler {    private Object target;    /**     * 绑定委托对象并返回一个代理类     *      * @param target     * @return     */    public Object bind(Object target) {        this.target = target;        // 取得代理对象        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);     }    /**     * 调用方法     */    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        if (method.getName().equals("force")) {            Object result = null;            System.out.println("开始工作");            // 执行方法            result = method.invoke(target, args);            System.out.println("工作结束");            return result;        } else {            return method.invoke(target, args);        }    }}

是不是感觉比之前牛X多了,当然目的还是找人要账,可能是我也可能是马六:

//JDK Dynamic Proxy DynamicLenderProxy proxy = new DynamicLenderProxy(); ILender bookProxy = (ILender) proxy.bind(new LiSiImpl()); long money = bookProxy.force("maliu"); System.out.println("要回了" + money + "块QB");
心平气和的找maliu要账。要回了100块QB

我们通常还可以把动态代理跟注解结合起来用,“帮会”越来越大,想立稳得提供多种业务,比如暴力要账,可以让人选择用什么样的暴力,是赤手空拳还是刀墙棍棒伺候:

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Force {        String weapon() default "拳头";}

有了这个注解可以在接口里使用:

/** * 借钱方 *  * @author moon *  */public interface ILender {    /**和平方式*/    public long peace(String name);    /**暴力方式*/    @Force(weapon = "AK47")    public long force(String name);}

改下DynamicLenderProxy里的invoke方法:

/**     * 调用方法     */    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        if (method.isAnnotationPresent(Force.class)) {            Force force = method.getAnnotation(Force.class);            String weapon = force.weapon();            System.out.println("用" + weapon + "开始工作");            Object result = method.invoke(target, args);            System.out.println("搞定收工");            return result;        } else {            return method.invoke(target, args);        }    }

拿AK47找人要钱谁敢不还:

用AK47开始工作以暴力方式找zhanjindong要账搞定收工要回了250块QB

(这里有个问题注解只能用在接口里,用在实现类里如何获取到呢?)

JDK动态代理的使用就是这么简单,下面就说为什么叫动态代理了。假设有一天我为实在还不了钱了,于是就想花钱找人把借钱给我的人干掉,于是我成了个凶手:

public interface IMurderer {    @Force(weapon = "沙漠之音")    public long kill(String name);}
public class JdzhanImpl implements IMurderer {    public void kill(String name) {        System.out.println("找我还钱?我要你" + name + "的命");    }}

恰好这时"JDK"拓展了业务,也干杀手这一行当了,于是乎当初找我还钱的人成了我雇的杀手,但是实现一点没动:

DynamicLenderProxy2 proxy = new DynamicLenderProxy2();  IMurderer murderer = (IMurderer) proxy.bind(new JdzhanImpl());  murderer.kill("LiSi");
用沙漠之音开始工作找我还钱?我要你LiSi的命搞定收工

好了,这个我胡扯的例子说完了,动态代理的好处也就体现出来了:

可以为不同的接口进行代理

如果我们用静态代理的话那么每个接口我们都得写一个代理类。

 

但是竟然动态为什么不更灵活点呢,JDK的动态代理还是需依赖接口的,接口就像一个契约或收据,你找我还钱最起码得有欠条吧,下篇文章介绍下Cglib动态代理,就是怎么在没有收据的情况下找人还钱。

 

 

转载于:https://www.cnblogs.com/zhanjindong/p/3730805.html

你可能感兴趣的文章
负载均衡(LB)集群 dr
查看>>
(转)直接拿来用!最火的iOS开源项目(一)
查看>>
div+css+js 树形菜单
查看>>
android EventBus 3.0 混淆配置
查看>>
我的友情链接
查看>>
DNS区域委派与转发
查看>>
Windows Server 2008 RemoteApp---发布应用程序
查看>>
白帽子技术分析会话劫持实战讲解
查看>>
我的友情链接
查看>>
yum的三种方式
查看>>
Redis分布式缓存安装和使用
查看>>
PHP环境搭建:Windows 7下安装配置PHP+Apache+Mysql环境教程以及注意事项
查看>>
20天精通 Windows 8:系列课程资料集
查看>>
html5 <figure> 标签
查看>>
linux的I/O多路转接select的fd_set数据结构和相应FD_宏的实现分析
查看>>
Mysql数据库InnoDB存储引擎的隔离级别
查看>>
开源监控软件 Hyperic 的两种插件
查看>>
TOMCAT
查看>>
无土栽培中的物联网技术应用
查看>>
div contenteditable="true"各个浏览器上的解析
查看>>