典型问答

Q:谈谈 Java 反射机制,动态代理是基于什么原理?

A:动态代理是运行时动态构建代理、动态处理代理方法调用的一种机制。动态代理[技术]广泛应用于产品开发,很多繁琐的重复编程,都可以被动态代理机制优雅地解决,比如包装RPC调用、面向切面编程(AOP)。
反射机制是Java语言提供的基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。通过反射,可以在运行时操作对象或类的元数据,比如获取某个对象的类定义,类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义(如访问限制)。
实现动态代理的方式很多,比如 JDK 动态代理,就是主要利用了反射机制。还有其他的实现方式,比如利用更高性能的字节码操作机制,类似 ASM、cglib(基于 ASM)、Javassist 等。

考点分析

考察知识点比较庞杂,拓展或深挖的内容非常多,比如:

  • 考察对反射机制的了解和掌握程度
  • 动态代理解决了什么问题,在业务系统中的应用场景是什么
  • JDK动态代理在设计和实现上与cglib等方式有什么不同,如何取舍

知识扩展

1.反射机制及其演进

反射最大的作用就是可以不在编译时知道某个对象的类型,而是在运行时通过提供完整的“包名+类名.class”得到。
功能

  • 运行时判断任意一个对象所属的类
  • 运行时构造任意一个类的对象
  • 运行时判断任意一个类所属的成员变量和方法
  • 运行时调用任意一个对象的方法

简单的讲,利用Java反射机制可以加载一个运行时才得知名称的class,获悉其构造方法,并生成其对象实体,能对其fields设值并唤起其methods。(Class类和java.lang.reflect包下的Field、Method、Constructor等,就是操作类和对象的元数据对应)

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

特点

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

2.动态代理

代理,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在两者之间起到中介的作用(可类比房屋中介,房东委托中介销售房屋、签订合同等)。

所谓动态代理,就是实现阶段不用关心代理谁,而是在运行阶段才指定代理哪个一个对象(不确定性)。如果是自己写代理类的方式就是静态代理(确定性)。

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

实现方式
实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了反射机制。还有其他的实现方式,比如利用字节码操作机制,类似 ASM、CGLIB(基于 ASM)、Javassist 等。

举例,常可采用的JDK提供的动态代理接口InvocationHandler来实现动态代理类。其中invoke方法是该接口定义必须实现的,它完成对真实方法的调用。通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。此外,我们常可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。

3.1 延伸-代理模式

3.2 延伸-编程语言分类角度(动态/静态,强类型/弱类型)

通常认为,Java是静态的强类型语言,但因为提供反射等机制,具备了动态语言的能力。

  • 分类角度一:动态类型和静态类型
    语言类型信息是在运行时检查,还是编译期检查
  • 分类角度二:强类型和弱类型
    不同类型变量赋值时,是否需要显示地(强制)进行类型转换

精选留言

一课一练