IT资讯
当前位置:摩信网 > IT资讯 >  活动互动

Java 动态代理详解

2020-04-08 00:14:56 木庄网络博客 编辑:丽丽 浏览数:35摩信网

本文摘自掘金-小旋锋,原文地址:https://juejin.im/post/5c1ca8df6fb9a049b347f55c,转载内容有删减,侵删。 动态代理在Java中有着广泛的应用,比如Spring ...

本文摘自掘金-小旋锋,原文地址:https://juejin.im/post/5c1ca8df6fb9a049b347f55c,转载内容有删减,侵删。

动态代理在Java中有着广泛的应用,比如Spring AOP、Hibernate数据查询、测试框架的后端mock、RPC远程调用、Java注解对象获取、日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等。

本文主要介绍Java中两种常见的动态代理方式:JDK原生动态代理CGLIB动态代理

由于Java动态代理与java反射机制关系紧密,请读者确保已经了解了Java反射机制,可参考上一篇文章《Java反射机制详解》。

代理模式

本文将介绍的Java动态代理与设计模式中的代理模式有关,什么是代理模式呢?

代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。

代理模式角色分为 3 种:

Subject(抽象主题角色):定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法;

RealSubject(真实主题角色):真正实现业务逻辑的类;

Proxy(代理主题角色):用来代理和封装真实主题;

代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层。

代理模式按照职责(使用场景)来分类,至少可以分为以下几类:

1、远程代理。 

2、虚拟代理。 

3、Copy-on-Write 代理。 

4、保护(Protect or Access)代理。 

5、Cache代理。 

6、防火墙(Firewall)代理。 

7、同步化(Synchronization)代理。 

8、智能引用(Smart Reference)代理等等。 

如果根据字节码的创建时机来分类,可以分为静态代理和动态代理: 

· 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。 

· 而动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件。

静态代理

我们先通过实例来学习静态代理,然后理解静态代理的缺点,再来学习本文的主角:动态代理。

编写一个接口 UserService ,以及该接口的一个实现类 UserServiceImpl

public interface UserService {
    public void select();   
    public void update();
}

public class UserServiceImpl implements UserService {  
    public void select() {  
        System.out.println("查询 selectById");
    }
    public void update() {
        System.out.println("更新 update");
    }
}

我们将通过静态代理对 UserServiceImpl 进行功能增强,在调用 selectupdate 之前记录一些日志。

写一个代理类 UserServiceProxy,代理类需要实现 UserService

public class UserServiceProxy implements UserService {
    private UserService target; // 被代理的对象

    public UserServiceProxy(UserService target) {
        this.target = target;
    }
    public void select() {
        before();
        target.select();    // 这里才实际调用真实主题角色的方法
        after();
    }
    public void update() {
        before();
        target.update();    // 这里才实际调用真实主题角色的方法
        after();
    }

    private void before() {     // 在执行方法之前执行
        System.out.println(String.format("log start time [%s] ", new Date()));
    }
    private void after() {      // 在执行方法之后执行
        System.out.println(String.format("log end time [%s] ", new Date()));
    }
}

客户端测试

public class Client1 {
    public static void main(String[] args) {
        UserService userServiceImpl = new UserServiceImpl();
        UserService proxy = new UserServiceProxy(userServiceImpl);

        proxy.select();
        proxy.update();
    }
}

输出

log start time [Thu Dec 20 14:13:25 CST 2018] 
查询 selectById
log end time [Thu Dec 20 14:13:25 CST 2018] 
log start time [Thu Dec 20 14:13:25 CST 2018] 
更新 update
log end time [Thu Dec 20 14:13:25 CST 2018] 

通过静态代理,我们达到了功能增强的目的,而且没有侵入原代码,这是静态代理的一个优点。 

静态代理的缺点

虽然静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也会暴露出来。 

1、 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式: 

· 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大

· 新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类

2、 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。 

如何改进?

当然是让代理类动态的生成啦,也就是动态代理

为什么类可以动态的生成?

这就涉及到Java虚拟机的类加载机制了,推荐翻看《深入理解Java虚拟机》7.3节 类加载的过程。

Java虚拟机类加载过程主要分为五个阶段:加载验证准备解析初始化

其中加载阶段需要完成以下3件事情:

1. 通过一个类的全限定名来获取定义此类的二进制字节流

2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

3. 在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据访问入口

由于虚拟机规范对这3点要求并不具体,所以实际的实现是非常灵活的,关于第1点,获取类的二进制字节流(class字节码)就有很多途径:

· 从ZIP包获取,这是JAR、EAR、WAR等格式的基础

· 从网络中获取,典型的应用是 Applet

· 运行时计算生成,这种场景使用最多的是动态代理技术,在 java.lang.reflect.Proxy 类中,就是用了 ProxyGenerator.generateProxyClass 来为特定接口生成形式为 *$Proxy 的代理类的二进制字节流

· 由其它文件生成,典型应用是JSP,即由JSP文件生成对应的Class类

· 从数据库中获取等等

所以,动态代理就是想办法,根据接口或目标对象,计算出代理类的字节码,然后再加载到JVM中使用。

分享到:

版权与免责声明:

凡未注明"稿件来源"的内容均为转载稿,本网转载出于传递更多信息的目的;如转载稿涉及版权问题,请作者联系我们,同时对于用户评论等信息,本网并不意味着赞同其观点或证实其内容的真实性;


本文地址:http://www.dbfrrf.com.cn/news/2020/04/08/325180635.html

转载本站原创文章请注明来源:摩信网

行业聚焦

微软:其47000位程序员每月制造近30000个bug

IT之家4月24日消息 微软详细介绍了他们如何利用机器学习模型处理其软件和服务中的BUG,“47000名开发人员每月产生近3万个Bug,”微软高级安全项目经理S...[详细]

OPPO Enco W31 真无线耳机正式发布:售价299元

IT之家4月13日消息 今天晚间OPPO正式举办了OPPO Ace2新品发布会,OPPO Enco W31真无线耳机也随之发布,并同步开售,售价299...[详细]

腾讯AI又创新纪录:ACL 2020入选27篇论文

近日,国际计算语言学协会年会(ACL,The Association for ComputationalLinguistics)在官网公布了ACL 2020的论...[详细]

【IT之家众测作品】小米AX3600路由器测评

本文系IT之家众测第六期作品。稿件内容、照片均为众测作者原创。首先感谢IT之家提供这次测评机会,有幸拿到了这款小米的最新产品——小米AX3600 AIoT路由器...[详细]

小米集团进军车联网,博泰逆势获融资

4月17日,车联网企业上海博泰(Pateo)获得中国科技公司小米集团B轮战略投资。雷锋网获悉,本次投资,小米以战略投资人注资博泰,投资金额以及具体股比尚未透露。...[详细]

智能时代

更多

1799 元至 2999 元,荣耀 Play4/Pro 5G 手机正式发布

 

IT之家6 月 3 日消息  今天下午,荣耀 Play4 系列新品发布会举行,荣耀正式发布了 Play4 Pr...[详细]

苹果 iPhone 11 最高降价 1600 元,iPhone 12 发布时将遭安卓 5G 手机四面围剿

 

IT之家5月17日消息 央视财经近期报道,今年上半年,国内手机市场有两个关键词:“5G围剿4G”以及“价格大战...[详细]

特斯拉更新Model Y和Model 3交付时间 最快5周到7周交货

 

受疫情影响,特斯拉弗里蒙特工厂被关闭,不过重新生产后,特斯拉更新了Model Y和Model 3交付时间,最快5周到7周...[详细]

Q1全球笔记本和平板电脑市场超预期 联想实现逆势双增长

 

近期,Strategy Analytics先后发布一季度全球平板和笔记本电脑出货量两份报告。尽管在疫情初期有些机构做出了...[详细]

工信部推进电信运营企业下降流量资费带动5G消费

 

  每日经济新闻记者:  咱们注意到,5G在疫情防控和复工复产的过程中发挥出了及其重要的效果,能否介绍一下当时5G建造的...[详细]

一周排行每月关注
北京十一选五开奖 重庆快乐10分一定牛走势图 浙江体彩6+1开奖结果查询果 pk10牛牛 体彩江苏7位数近30期 辽宁快乐十二二胆全托 黑龙江6+1预测 心悦吉林麻将下载二维码 江西开奖结果十一选 黑龙江福彩22箱开奖结果 极速赛车怎么选数字呢 青海快3中奖助手 山东十一选五*遗漏 湖北11选5第19061529期 内蒙古快3走势图和尾 广东省南粤风采36 7 九游旧版2015