JAVA语言动态代理模式浅析
小标 2018-07-19 来源 : 阅读 696 评论 0

摘要:本文主要向大家介绍了JAVA语言动态代理模式浅析,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了JAVA语言动态代理模式浅析,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

Java动态代理模式浅析

· Java代理设计模式 - 静态代理

· Java中的动态代理 - 调用处理器

代理设计模式的UML图:

 

我将首先介绍Java中的各种代理实现方法

Java代理设计模式 - 静态代理

这个例子非常简单,只有一个方法wirteCode的接口IDeveloper:

public interface IDeveloper {

    public void writeCode();

}// 实现这个接口的类:public class Developer implements IDeveloper{

    private String name;

    public Developer(String name){

        this.name = name;

    }

    @Override

    public void writeCode() {

        System.out.println("Developer " + name + " writes code");

    }

}

测试代码:

public class DeveloperTest {

    public static void main(String[] args) {

        IDeveloper jerry = new Developer("Jerry");

        jerry.writeCode();

    }

}

测试输出:

Developer Jerry writes code

现在麻烦的是,Jerry的领导因为团队中的开发者像Jerry一样没有编写技术文档,所以并不满意。经过讨论后,整个团队达成协议,相关文档必须与代码一起提供。

为了迫使开发人员编写文档而不直接对现有的实现类Developer进行修改,现在就可以使用静态代理来实现:

// 创建一个和Developer类实现同样接口的类public class DeveloperProxy implements IDeveloper{

    private IDeveloper developer;

    // 引用Developer类对象

    public DeveloperProxy(IDeveloper developer){

        this.developer = developer;

    }

    @Override

    public void writeCode() {

        System.out.println("Write documentation...");

        this.developer.writeCode();

    }

}

测试代码:

public class DeveloperTest {

    public static void main(String[] args) {

        Developer jerry = new Developer("jerry");

        DeveloperProxy jerryproxy = new DeveloperProxy(jerry);

        jerryproxy.writeCode();

    }

}

测试输出:

Write documentation...

Developer jerry writes code

静态代理的优点

假设你希望在不修改原始类代码的情况下增强现有的稳定实现,你可以创建一个代理类,并将原始实现封装为代理中的私有属性。增强的功能是在代理类中完成的,对现有的代码是完全透明的。回到上面的示例,客户端代码并不关心它用来调用writeCode()方法的变量是否指向真正的开发人员或开发人员代码。

 

优点:

1. 易于实施和理解

2. 原始实现与其代理之间的关系在编译时已经确定,运行时没有额外的开销。

静态代理的缺点

我们仍然使用这个例子来说明。
假设现在缺失文档的问题在QA同事中仍然存在。如果我们想通过静态代理来解决这个问题,那么必须引入另一个代理类。

这是测试人员的接口:

public interface ITester {

    public void doTesting();

}// ITester 接口的实现类:public class Tester implements ITester {

    private String name;

 

    public Tester(String name){

        this.name = name;

    }

    @Override

    public void doTesting() {

        System.out.println("Tester " + name + " is testing code");

    }

}

测试人员代理:

public class TesterProxy implements ITester{

    private ITester tester;

    public TesterProxy(ITester tester){

        this.tester = tester;

    }

    @Override

    public void doTesting() {

        System.out.println("Tester is preparing test documentation...");

        tester.doTesting();

    }

}

测试代码和输出:

 

从Tester代理的源代码中我们可以很容易的观察到它与开发人员具有完全相同的逻辑。如果又过了一段时间,我们必须为软件交付过程中的其他同事建立文档,我们必须一次又一次的引入新的静态代理类,这会导致静态代理类变得十分庞大。

Java中的动态代理 - 调用处理器

现在我通过代理类EnginnerProxy来为所有的具体角色提供代理服务,而不是单独为每个原始实现类设置专用的静态代理类。

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

public class EnginnerProxy implements InvocationHandler{

    Object obj;

    public Object bind(Object obj)

    {

        this.obj = obj;

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj

                .getClass().getInterfaces(), this);

    }

 

    @Override

    public Object invoke(Object proxy, Method method, Object[] args)

            throws Throwable

    {

        System.out.println("Enginner writes document");

        Object res = method.invoke(obj, args);

        return res;

    }

}

主要笔记:

1. 不是从具有业务接口(IDeveloper或ITester)的专用接口继承,而是在此变体中,通过代理继承自JDK提供的技术接口InvocationHandler。

2. 为了确保通用代理可以适用于所有可能的具体实现类,在代理中定义了具有泛型类型的Object变量。

3. 调用代理实例的接口方法时,它将被InvocationHandler中定义的invoke方法拦截,其中由应用程序开发人员声明的增强逻辑与由Java Reflection调用的原始逻辑一起调用。

下面是如何使用InvocationHandler设计的动态代理和测试输出:

 

动态代理类的限制

虽然这个变体成功的避免了静态代理中的重复缺陷,但是它仍然有一个局限性,它无法使用不是从接口继承的实现类,就是说,使用动态代理类,原始类必须先要实现一个或多个接口,这个接口也就是代理接口。

考虑下面的例子,产品所有者没有实现任何接口:

public class ProductOwner {

    private String name;

    public ProductOwner(String name){

        this.name = name;

    }

    public void defineBackLog(){

        System.out.println("PO: " + name + " defines Backlog.");

    }

}

以下代码在IDE中没有任何语法错误:

ProductOwner po = new ProductOwner("Ross");

ProductOwner poProxy = (ProductOwner) new EnginnerProxy().bind(po);

poProxy.defineBackLog();

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程