谈谈 Java 反射机制, 动态代理是基于什么原理? 小编整理了一些 java 进阶学习资料和面试题, 需要资料的请加 JAVA 高阶学习 Q 群: 701136382 这是小编创建的 java 高阶学习交流群, 加群一起交流学习深造. 群里也有小编整理的 2019 年最新最全的 java 高阶学习资料!
反射机制
Java 语言提供的一种基础功能, 赋予程序在运行时自省 (introspect, 官方用语) 的能力. 可以在运行时通过提供完整的 "包名 + 类名. class" 得到某个对象的类型.
功能
在运行时能判断任意一个对象所属的类.
在运行时能构造任意一个类的对象.
在运行时判断任意一个类所具有的成员变量和方法.
在运行时调用任意一个对象的方法.
利用 Java 反射机制我们可以加载一个运行时才得知名称的 class, 获悉其构造方法, 并生成其对象实体, 能对其 fields 设值并唤起其 methods.
应用场景
通过反射我们可以直接操作类或者对象, 比如获取某个对象的类定义, 获取类声明的属性和方法, 调用方法或者构造对象, 甚至可以运行时修改类定义.
通过运行时操作元数据或对象, Java 可以灵活地操作运行时才能确定的信息.
反射技术常用在各类通用框架开发中. 因为为了保证框架的通用性, 需要根据配置文件加载不同的对象或类, 并调用不同的方法, 这个时候就会用到反射 -- 运行时动态加载需要加载的对象.
特点:
由于反射会额外消耗一定的系统资源, 因此如果不需要动态地创建一个对象, 那么就不需要用反射. 另外, 反射调用方法时可以忽略权限检查, 因此可能会破坏封装性而导致安全问题.
动态代理
一种方便运行时动态构建代理, 动态处理代理方法调用的机制. 为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下, 一个对象不适合或者不能直接引用另一个对象, 而代理对象可以在两者之间起到中介的作用(可类比房屋中介, 房东委托中介销售房屋, 签订合同等).
所谓动态代理, 就是实现阶段不用关心代理谁, 而是在运行阶段才指定代理哪一个对象(不确定性). 如果是自己写代理类的方式就是静态代理(确定性).
组成要素:
1, 抽象类接口
2, 被代理类(具体实现抽象接口的类)
3, 动态代理类: 实际调用被代理类的方法和属性的类
应用场景
很多场景都是利用类似机制做到的, 比如用来包装 RPC 调用, 面向切面的编程(AOP). 其是反射延伸出来的一种广泛应用于产品开发中的技术, 很多繁琐的重复编程, 都可以被动态代理机制优雅地解决
实现方式
1,JDK 自身提供的动态代理, 主要利用了反射机制.
2, 利用传更高性能的字节码操作机制, 类似 ASM,cglib(基于 ASM),Javassist 等.
举例, 常可采用的 JDK 提供的动态代理接口 InvocationHandler 来实现动态代理类. 其中 invoke 方法是该接口定义必须实现的, 它完成对真实方法的调用. 通过 InvocationHandler 接口, 所有方法都由该 Handler 来进行处理, 即所有被代理的方法都 InvocationHandler 接管实际的处理任务. 此外, 我们常可以在 invoke 方法实现中增加自定义的逻辑实现, 实现对被代理类的业务逻辑无侵入.
知识扩展:
代理模式(通过代理静默地解决一些业务无关的问题, 比如远程, 安全, 事务, 日志, 资源关闭...... 让应用开发者可以只关心他的业务)
静态代理: 事先写好代理类, 可以手工编写, 也可以用工具生成. 缺点是每个业务类都要对应一个代理类, 非常不灵活.
动态代理: 运行时自动生成代理对象. 缺点是生成代理代理对象和调用代理方法都要额外花费时间.
JDK 动态代理: 基于 Java 反射机制实现, 必须要实现了接口的业务类才能用这种办法生成代理对象. 新版本也开始结合 ASM 机制.
cglib 动态代理: 基于 ASM 机制实现, 通过生成业务类的子类作为代理类.
Java 反射机制的常见应用: 动态代理 (AOP,RPC), 提供第三方开发者扩展能力(Servlet 容器, JDBC 连接), 第三方组件创建对象(DI) 等等
反射机制:
反射提供了 AccessibleObject.setAccessible?(boolean flag). 它的大多数子类重写了这个方法, 这里的所谓 accessible 可以理解成修饰成员的 public,protected,private, 这意味着我们可以在运行时修改成员访问限制!
setAccessible 的应用场景:
1, 我们为一个 Java 实体对象, 运行时自动生成 setter,getter 的逻辑, 这是加载或者持久化数据非常必要的, 框架通常可以利用反射做这个事情, 而不需要开发者手动写类似的重复代码.
2, 绕过 API 访问控制. 我们日常开发时可能被迫要调用内部 API 去做些事情, 比如, 自定义的高性能 NIO 框架需要显式地释放 DirectBuffer, 使用反射绕开限制是一种常见办法.
动态代理:
动态代理解决了什么问题?
1, 它是一个代理机制(代理可以看作是对调用目标的一个包装). 通过代理, 我们对目标代码的调用不是直接发生的, 而是通过代理完成.
2, 通过代理可以让调用者与实现者之间解耦. 比如进行 RPC 调用, 框架内部的寻址, 序列化, 反序列化等, 对于调用者往往是没有太大意义的, 通过代理, 可以提供更加友善的界面.
来源: http://www.bubuko.com/infodetail-2927473.html