Java核心技术面试精讲
杨晓峰
前Oracle首席工程师
立即订阅
43250 人已学习
课程目录
已完结 43 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 以面试题为切入点,有效提升你的Java内功
免费
模块一 Java基础 (14讲)
第1讲 | 谈谈你对Java平台的理解?
第2讲 | Exception和Error有什么区别?
第3讲 | 谈谈final、finally、 finalize有什么不同?
第4讲 | 强引用、软引用、弱引用、幻象引用有什么区别?
第5讲 | String、StringBuffer、StringBuilder有什么区别?
第6讲 | 动态代理是基于什么原理?
第7讲 | int和Integer有什么区别?
第8讲 | 对比Vector、ArrayList、LinkedList有何区别?
第9讲 | 对比Hashtable、HashMap、TreeMap有什么不同?
第10讲 | 如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?
第11讲 | Java提供了哪些IO方式? NIO如何实现多路复用?
第12讲 | Java有几种文件拷贝方式?哪一种最高效?
第13讲 | 谈谈接口和抽象类有什么区别?
第14讲 | 谈谈你知道的设计模式?
模块二 Java进阶 (16讲)
第15讲 | synchronized和ReentrantLock有什么区别呢?
第16讲 | synchronized底层如何实现?什么是锁的升级、降级?
第17讲 | 一个线程两次调用start()方法会出现什么情况?
第18讲 | 什么情况下Java程序会产生死锁?如何定位、修复?
第19讲 | Java并发包提供了哪些并发工具类?
第20讲 | 并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?
第21讲 | Java并发类库提供的线程池有哪几种? 分别有什么特点?
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
第23讲 | 请介绍类加载过程,什么是双亲委派模型?
第24讲 | 有哪些方法可以在运行时动态生成一个Java类?
第25讲 | 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?
第26讲 | 如何监控和诊断JVM堆内和堆外内存使用?
第27讲 | Java常见的垃圾收集器有哪些?
第28讲 | 谈谈你的GC调优思路?
第29讲 | Java内存模型中的happen-before是什么?
第30讲 | Java程序运行在Docker等容器环境有哪些新问题?
模块三 Java安全基础 (2讲)
第31讲 | 你了解Java应用开发中的注入攻击吗?
第32讲 | 如何写出安全的Java代码?
模块四 Java性能基础 (3讲)
第33讲 | 后台服务出现明显“变慢”,谈谈你的诊断思路?
第34讲 | 有人说“Lambda能让Java程序慢30倍”,你怎么看?
第35讲 | JVM优化Java代码时都做了什么?
模块5 Java应用开发扩展 (4讲)
第36讲 | 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
第37讲 | 谈谈Spring Bean的生命周期和作用域?
第38讲 | 对比Java标准NIO类库,你知道Netty是如何实现更高性能的吗?
第39讲 | 谈谈常用的分布式ID的设计方案?Snowflake是否受冬令时切换影响?
周末福利 (2讲)
周末福利 | 谈谈我对Java学习和面试的看法
周末福利 | 一份Java工程师必读书单
结束语 (1讲)
结束语 | 技术没有终点
Java核心技术面试精讲
登录|注册

第6讲 | 动态代理是基于什么原理?

杨晓峰 2018-05-17
编程语言通常有各种不同的分类角度,动态类型和静态类型就是其中一种分类角度,简单区分就是语言类型信息是在运行时检查,还是编译期检查。
与其近似的还有一个对比,就是所谓强类型和弱类型,就是不同类型变量赋值时,是否需要显式地(强制)进行类型转换。
那么,如何分类 Java 语言呢?通常认为,Java 是静态的强类型语言,但是因为提供了类似反射等机制,也具备了部分动态类型语言的能力。
言归正传,今天我要问你的问题是,谈谈 Java 反射机制,动态代理是基于什么原理?

典型回答

反射机制是 Java 语言提供的一种基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。
动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装 RPC 调用、面向切面的编程(AOP)。
实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类似 ASM、cglib(基于 ASM)、Javassist 等。

考点分析

这个题目给我的第一印象是稍微有点诱导的嫌疑,可能会下意识地以为动态代理就是利用反射机制实现的,这么说也不算错但稍微有些不全面。功能才是目的,实现的方法有很多。总的来说,这道题目考察的是 Java 语言的另外一种基础机制: 反射,它就像是一种魔法,引入运行时自省能力,赋予了 Java 语言令人意外的活力,通过运行时操作元数据或对象,Java 可以灵活地操作运行时才能确定的信息。而动态代理,则是延伸出来的一种广泛应用于产品开发中的技术,很多繁琐的重复编程,都可以被动态代理机制优雅地解决。
从考察知识点的角度,这道题涉及的知识点比较庞杂,所以面试官能够扩展或者深挖的内容非常多,比如:
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java核心技术面试精讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(66)

  • 肖一林
    提一些建议:应该从两条线讲这个问题,一条从代理模式,一条从反射机制。不要老担心篇幅限制讲不清问题,废话砍掉一些,深层次的内在原理多讲些(比如asm),容易自学的扩展知识可以用链接代替
    代理模式(通过代理静默地解决一些业务无关的问题,比如远程、安全、事务、日志、资源关闭……让应用开发者可以只关心他的业务)
        静态代理:事先写好代理类,可以手工编写,也可以用工具生成。缺点是每个业务类都要对应一个代理类,非常不灵活。
        动态代理:运行时自动生成代理对象。缺点是生成代理代理对象和调用代理方法都要额外花费时间。
            JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。新版本也开始结合ASM机制。
            cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类。
    Java 发射机制的常见应用:动态代理(AOP、RPC)、提供第三方开发者扩展能力(Servlet容器,JDBC连接)、第三方组件创建对象(DI)……
    我水平比较菜,希望多学点东西,希望比免费知识层次更深些,也不光是为了面试,所以提提建议。

    作者回复: 谢谢反馈,类似ASM这种字节码操纵是有单独章节覆盖的,前面基础篇有个整体印象,免得陷入细节;Java内部动态生成还有其他领域,比如Lambda实现机制,个人认为一起分析会连贯一些

    2018-05-17
    1
    424
  • 公号-代码荣耀
    反射与动态代理原理

    1 关于反射
    反射最大的作用之一就在于我们可以不在编译时知道某个对象的类型,而在运行时通过提供完整的”包名+类名.class”得到。注意:不是在编译时,而是在运行时。

    功能:
    •在运行时能判断任意一个对象所属的类。
    •在运行时能构造任意一个类的对象。
    •在运行时判断任意一个类所具有的成员变量和方法。
    •在运行时调用任意一个对象的方法。
    说大白话就是,利用Java反射机制我们可以加载一个运行时才得知名称的class,获悉其构造方法,并生成其对象实体,能对其fields设值并唤起其methods。

    应用场景:
    反射技术常用在各类通用框架开发中。因为为了保证框架的通用性,需要根据配置文件加载不同的对象或类,并调用不同的方法,这个时候就会用到反射——运行时动态加载需要加载的对象。

    特点:
    由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

    2 动态代理
    为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在两者之间起到中介的作用(可类比房屋中介,房东委托中介销售房屋、签订合同等)。
    所谓动态代理,就是实现阶段不用关心代理谁,而是在运行阶段才指定代理哪个一个对象(不确定性)。如果是自己写代理类的方式就是静态代理(确定性)。

    组成要素:
    (动态)代理模式主要涉及三个要素:
    其一:抽象类接口
    其二:被代理类(具体实现抽象接口的类)
    其三:动态代理类:实际调用被代理类的方法和属性的类

    实现方式:
    实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了反射机制。还有其他的实现方式,比如利用字节码操作机制,类似 ASM、CGLIB(基于 ASM)、Javassist 等。
    举例,常可采用的JDK提供的动态代理接口InvocationHandler来实现动态代理类。其中invoke方法是该接口定义必须实现的,它完成对真实方法的调用。通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。此外,我们常可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。
    2018-05-17
    6
    204
  • 刘方杰
    哎,阅读越来越困难了,我离核心是不是太远了。
    2018-05-18
    108
  • 天使
    没涉及到原理,proxy到底是如何实现的,运行时拦截?cglib是编译时对类进行织入?要是更细一些就好了
    2018-05-17
    105
  • 云学
    看了好多篇文章,总体感觉是比较累,无论读者是否具有java背景,都应该让他看懂,而不是越看越糊涂,疑问反而更多了

    作者回复: 非常感谢,读者基础不同,我尽量兼顾并增加基础的介绍,因为也有反馈希望可以更全面、深入...
    有好的建议请不吝赐教

    2018-06-09
    41
  • Douglas
    好像和啥原理没啥关系吧,总结来说就是jdk 自身的反射机制或用第三方库,哪哪看到的都这样说,一笔带过

    作者回复: 谢谢反馈,字节码操作、运行时拦截、加载期编织 、Java agent等,会和Aop单独介绍,那些内容不是几句话说得完

    2018-05-17
    25
  • ai~ wen
    对于我这初学者,读着就懵了
    2018-05-21
    24
  • Douglas
    比较期待大神讲讲动态代理的原理是什么,对性能会带来什么影响,有没有什么问题需要规避,谢谢
    2018-05-17
    17
  • 雷赟
    何为反射?

    反射是指计算机程序在运行时可以访问、检测和修改它本身状态或行为的一种能力。比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

    文章中提到了“自省”它与反射是有区别的,“自省”机制仅指程序在运行时对自身信息(元数据)的检测,而反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。

    通过反射的运行时可以访问、检测和修改自身状态的特性,也就出现了动态代理。

    一个小白对反射的使用场景(受限于业务能力):

    在一个程序中有两个类A、B,整个程序的运行都由 B 类来承担,A 类的所要做的工作是满足B的要求,如果在没有反射这种机制的条件下实现这个程序就会,既要把 B 类中的对整个程序运行逻辑进行编写,还要回到 A 类中对 B 的工作进行人工手动辅助,这时只要 B 的任何改动都会影响到 A 。

    若在有了反射或代理之后 A 的代码就可以自己去访问、检测 B ,从而自动的修改 A 自身的状态来辅助 B。



    作者在评论中提到实现后续单独说明,我想到时就可以知道:代码是如何实现程序在运行时的访问、检测和行为的修改了。
    2018-05-22
    1
    14
  • 言志
    采用cglib方式的动态代理还有个缺点:不能应用到被代理对象的final方法上。
    我在多数据源项目中自动切换数据源功能用到了
    2018-05-17
    1
    14
  • bigfish
    本来资质愚笨,看不懂很多东西的原理.想进来学习一下,jdk动态代理的原理和cglib代理原理等一些原理性的东西(其他章节也是如此).发现听到原理性的东西不多都是一带而过.其实您做的课件针对很多点都是一带而过,听到某个名词一下来了兴趣继续一听结束了.我们都知道Java很大很多可以研究的,其实我们想听的很多是一些点的原理,讲完原理在结合实际应用阐述一下.也许我们就会有些豁然明朗的感觉.希望能理解一下!!!

    作者回复: 谢谢反馈,后面类加载章节介绍了两者底层机制,照顾下不同基础的读者

    2018-07-08
    1
    10
  • Fly
    对于初学者表示我查了好多文章才看懂这篇~ 需要先做功课~


    * java是静态的强类型语言,因为也提供了反射等机制,也具备动态类型语言的能力。
    >要理解动态代理需要先了解几个方面:

    ### 反射机制 java.lang.reflect
    * 解释:运行时程序的自省。通过运行时操作元数据和对象,java可以灵活地操作运行时才能确定的信息。
    * 作用
        * 使用反射可以直接操作对象
        * 获取某个对象的类定义
        * 获取类声明属性和方法
        * 调用方法或者构造对象
        * 运行时修改类定义
    * 缺点:
        * 性能:能不用反射实现的需求则尽可能避免使用。性能低。
        * 安全:反射需要运行时权限,在安全管理器(SecurityManager)下可能不能运行
        * 内部接触:反射可以访问private因此可能导致副作用,破坏可移植性,打破抽象
    * 场景:动态代理(AOP、RPC)、第三方开发者扩展能力、第三方组件创建对象。
    * 用法:
    ```java
    Class clazz = Class.forName("com.playcrab.war.gvg.gvgLogic");
    Constructor[] conArray = clazz.getConstructors(); //获取所有公有构造方法
    ```

    ### RPC(Remote procedure call)
    * 一种编程模型,不限制底层实现(RMI、网络httpClient/socket、动态代理、反射)
    * 远程过程调用,多用在分布式部署中,将某个模块部署到独立服务器上,通过RPC实现客户端无感知的各服务之间的调用。比如阿里的Dubbo
    * [简书-RPC介绍](https://www.jianshu.com/p/2accc2840a1b)

    ### AOP(Aspect Oriented Programming)
    * 面相切面编程,对象与对象之间、模块与模块之间都是一个切面。减少代码量的一种方式,是OOP的一个延续。所以通过动态代理也可以实现AOP编程。Spring AOP
    * 大幅提高代码的抽象度和复用度,让我们从繁琐的事项中抽身出来。

    ### 动态代理
    * 实现方式:JDK自身提供的动态代理(java.lang.reflect.Proxy)利用了反射、高性能的字节码操作机制类似ASM、cglib、javaassist等。
    * 场景:包装RPC调用、面向切面编程AOP等。
    * 区别与优势:
        * JDK Proxy
            1. 被调用者必须实现接口。
            2. JDK本身支持可能更加可靠
            3. 代码实现简单。
            4. 平滑升级JDK,而字节码类库需要进行更新以保证可用。
            5. 新版本JDK也使用ASM提高性能。
        * 类cglib
            1. cglib没有实现接口的限制
            2. 只操作我们关心的类,不需要为其他相关类增加工作量
            3. 基于ASM字节码,高性能。
            4. 通过生成业务类的子类作为代理类。
    * 类似python重写__getattr__、php的魔术方法__call 将对象中不同的方法统一到一个处理函数。对于调用者毫无察觉,和调用本地方法一般,被代理的类不一定是本地类,也可以通过抽象方式代理远程主机上的类,实现RPC。
    * 也可以自己实现业务类的代理类,比较繁琐需要挨个实现每个方法的转发。称为静态代理
    2019-07-02
    1
    9
  • 约书亚
    先回答问题:
    99%的Java程序员应该都间接使用了AOP。自己项目里直接编写的,比如调用追踪,通用日志, 自动重试
    反射和AOP真是双刃剑效果拔群的技术。从MVC开始约定胜过配置的开发理念大行其道,ORM自动映射,plugin模式,到现在的spring + boot +cloud 的declarative编程大量基于此实现,可以说没有反射和AOP就没有Java的今天。反面就是,自己想进行定制化的改造封装真挺苦逼
    再提问题:
    1. 听到过个说法,反射慢因为一是获取Field,Method等要进行元数据的查找,这里有字符串匹配操作。二是Invoke时,要进行一些安全性上的检查。这种说法对么?JVM在解释执行的时候就不做一些操作内存操作的检查了么?如果不对,那原因是什么?还有没有其他?
    2. 以前写C#的,里面可以拼表达式树,运行时生成一个函数(不需要有对象),理论上性能是和手写代码一样的,但可以缓存起来。这解决的是手写中间代码太难的问题。请问Java有这种类似的功能嘛?

    作者回复: 1.基本如此;反射是相对保证类型安全的,我觉得要比较也是和methodhandle之类对比,那个更是接近jvm内部的黑盒,性能更好
    2.你是说lambda?也是需要jvm生成call site,然后invokedynamic之类调用,所以首次调用开销明显,C#不了解,不过动态生成的感觉都是如此吧;
    这东西目前没有cache,如果你说的是存储在文件系统;未来,嘿嘿……

    这些太零碎,说过了会有单独章节介绍,不然没基础的就晕了,还用不上


    2018-05-17
    8
  • 正光
    整体感觉讲的太浅,水上漂的感觉

    作者回复: 具体底层细节在jvm字节码操纵那一讲,难度把握不准请见谅

    2018-08-04
    7
  • THROW
    老师可以在分享结束时推荐一些好的文章,书籍甚至演讲之类的么?

    作者回复: 没问题,喜欢底层,去查查JavaOne,FOSDEM,jvmsummit等

    2018-05-17
    7
  • yoo
    您好,我一直关注您的文章,但是每次都觉得不是很理解。可不可以在以后的文章中讲一些实际的应用场景。
    2018-08-08
    6
  • godtrue
    恩,如大部分同学的感受一样,不够细致,一些概念点到为止了
    当然,对于开阔眼界是大大的帮助的,动态代理这个平时编码没直接写过,各种框架的实现是基本用到的,感觉都是针对字节码进行的操作,可能操作的方式有些不同。JAVA源码是写个人看的,是编译器的输入材料,Java字节码是准备给JVM来加载识别的,是机器码的待转换材料,主要是JVM来操作。
    框架为了其通用性,一定是不知道对应业务代码都是有哪些类和名字的,不过类想发挥作用总是要到JVM内才行的,类的全路径名为寻找对应的提供了线索,所以,将类名告诉框架,然后按照约定的形式编写,框架就能执行一些只有到执行时才知道的类的功能了。
    这个就是我对动态代理和框架功能的理解,至于怎么获取类名,以及如何获取对应的在执行时才知道的类,估计就复杂了,至少对人如此,对JVM可能简单一些。反射是一种方式,直接根据类名的字节码也许也能找到吧!这个就是底层的原理啦!这也是期待从老师那里了解的
    2018-12-13
    5
  • Loren
    我把文章中的代理的代码copy到本地运行,debug运行时我打了几个断点,运行后输出了很多次Invoking sayHello是为什么
    2018-12-12
    4
  • 灰飞灰猪不会灰飞.烟灭
    cglib是怎么实现对目标对象的拦截的呢?

    作者回复: 计划单独介绍

    2018-05-17
    4
  • clz1341521
    spring是通过设置target-class是否为true,来决定是否强制使用cglib。
    静态代理:事先写好代理类,可以手工编写,也可以用工具生成。缺点是每个业务类都要对应一个代理类,非常不灵活。
        动态代理:运行时自动生成代理对象。缺点是生成代理代理对象和调用代理方法都要额外花费时间。
            JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。新版本也开始结合ASM机制。
            cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类。
    Java 发射机制的常见应用:动态代理(AOP、RPC)
    2018-07-25
    2
收起评论
66
返回
顶部