java反射与动态代理的理解
一、什么是反射机制?
反射的官方定义是这样的:在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制。
讲的通俗一点的话就是,对于jvm来说,.java文件必须要先编译为.class文件才能够被jvm执行,所以在编译为.class文件的过程中,对象的类型都会被指定好,比如说 User user。那么如果说我想在代码运行的过程中获取到对象的类型呢?或者说程序在运行过程中如何载入一个特定的类呢?这就涉及到了java的反射机制了,反射提供了一套能够让我们在代码运行时也能获取到类型属性的方法。
二、反射的使用
jdk提供了三种方式获取一个对象的Class,就User user来说
1.user.getClass(),这个是Object类里面的方法
2.User.Class属性,任何的数据类型,基本数据类型或者抽象数据类型,都可以通过这种方式获取类
3.Class.forName(""),Class类提供了这样一个方法,让我们通过类名来获取到对象类
这三种方法用的最多的就是第三种,那么获取到类之后,Class类提供了很多获取类属性,方法,构造方法的api。
1.获取所有的属性
//获取整个类
Class c = Class.forName("java.lang.Integer");
//获取所有的属性?
Field[] fs = c.getDeclaredFields(); //定义可变长的字符串,用来存储属性
StringBuffer sb = new StringBuffer();
//通过追加的方法,将每个属性拼接到此字符串中
//最外边的public定义
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
//里边的每一个属性
for(Field field:fs){
sb.append("\t");//空格
sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
sb.append(field.getName()+";\n");//属性的名字+回车
} sb.append("}"); System.out.println(sb);
2.获取特定的属性
//获取类
Class c = Class.forName("User");
//获取id属性
Field idF = c.getDeclaredField("id");
//实例化这个类赋给o
Object o = c.newInstance();
//打破封装
idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
//给o对象的id属性赋值"110"
idF.set(o, "110"); //set
//get
System.out.println(idF.get(o));
3.获取方法
getDeclaredMethods() 获取所有的方法 getReturnType() 获得方法的放回类型 getParameterTypes() 获得方法的传入参数类型 getDeclaredMethod("方法名",参数类型.class,……) 获得特定的方法 getDeclaredConstructors() 获取所有的构造方法 getDeclaredConstructor(参数类型.class,……) 获取特定的构造方法 getSuperclass() 获取某类的父类 getInterfaces() 获取某类实现的接口
三、反射的作用和动态代理
反射作用总结就是:1.动态地创建类的实例,将类绑定到现有的对象中,或从现有的对象中获取类型。2.应用程序需要在运行时从某个特定的程序集中载入一个特定的类。
那么什么是动态代理呢?先给出百度的答案:动态代理,就是根据对象在内存中加载的Class类创建运行时类对象,从而调用代理类方法和属性。
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。而代理模式又分为静态代理和动态代理,先说静态代理。
静态代理通俗点将就是自己手写一个代理类,而动态代理则不用我们手写,而是依赖于java反射机制,下面以一个demo举例。
demo结构如图:
Subject是一个普通接口,里面有个抽象的doSomething()的方法,而SubjectImpl.java是它的普通的实现类,如下所示。
而HandProxy.java就是SubjectImpl的静态代理类,代替了SubjectImpl完成doSomething的工作,如下所示
这样做的好处是对于doSomething方法来说,我用静态代理类来实现,可以任意的在其中插入我需要额外做的事情,比如说记录日志。
那么AutoProxy.java就是动态代理类了,具体如下所示。
这里面首先想要做到动态代理,必须先实现这个InvocationHandler接口,然后我们主要看bind方法,参数tar是一个Object类型的对象,也就是需要被代理的对象SubjectImpl,
方法里面有一个Proxy类,这个Proxy类提供了很多方法,这里我们用的是newProxyInstance方法,它有三个参数,第一个是被代理类的类构造器,第二个指的是被代理类的接口,也就是Subject接口,第三个是实现这个代理的类,这里就是本类。具体的来说,这个方法执行了下面三步:
1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。
2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类传入。
3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的subject.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成Subject类型来调用接口中定义的方法。
而在调用每个代理类每个方法的时候,都用反射去调h的invoke方法(也就是我们自定义的InvocationHandler的子类中重写的invoke方法),用参数传递了代理类实例、接口方法、调用参数列表,这样我们在重写的invoke方法中就可以实现对所有方法的统一包装了。
总结一下,静态代理的优点是清晰易懂,但是如果说业务代码很多,那么在代理类里面必须全部重新调用一遍,很麻烦。而动态代理,利用java反射机制,动态的生成了一个代理类,直接调用代理方法即可。
四、总结
反射这一块是博主最近在看框架源码的时候总是遇到这类问题所以刻意去整理了一下,里面有些东西其实我也研究的不是很深刻,动态代理这边的源码还有待深入挖掘,若有大神发现写的不对的地方,还请多多指教,谢谢。
java反射与动态代理的理解的更多相关文章
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
- Java反射和动态代理
Java反射 反射机制 RTTI 编译器在编译时打开和检查*.class文件 反射机制 运行时打开和检查*.class文件 Java反射常见的方法 java反射的应用 setAccessible(bo ...
- Java反射机制动态代理
1.什么事反射机制动态代理 在一段代码的前后动态执行其他操作,比如有一个方法是往数据库添加一个记录,我们可以通过动态代理,在操作数据库方法的前和后添加代码执行打开数据库连接和关闭数据库连接. 2.演示 ...
- java反射和动态代理实现与原理详细分析
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 代理模式是常用的java设计模式, ...
- java反射实现动态代理
参考:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html http://my.oschina.net/lyp3314/b ...
- 深入分析Java反射(四)-动态代理
动态代理的简介 Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分 ...
- Java反射与动态代理
Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制.java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模块之间的 ...
- Java反射 - 3(动态代理)
动态代理是对包装模式的升级,可以动态的传入需要代理的对象实现代理 准备如下 1. 被代理类的接口 2.被代理类 3.处理器:InvocationHandler 4.代理调用:Proxy.newInst ...
- Java 反射之动态代理
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt205 利用Java反射机制你可以在运行期动态的创建接口的实现.java.la ...
随机推荐
- 设计模式之观察者模式(c++)
Observer 模式应该可以说是应用最多.影响最广的模式之一,因为 Observer 的一个实例 Model/View/Control( MVC) 结构在系统开发架构设计中有着很重要的地位和意义, ...
- [smf]论坛实现编辑器附件插入的插件
smf论坛代码的相关介绍,可以参见博客园的其他文章,这里不再详细说明了. 插件功能: 在帖子里的任何位置插入附件图片. 关于安装: 该插件已经经过“维尼熊的百宝箱”的修改,在新版本SMF 2.0.14 ...
- 记录使用 Cake 进行构建并制作 nuget 包
书接上一回(https://www.cnblogs.com/h82258652/p/4898983.html)?[手动狗头] 前段时间折腾了一下,总算是把我自己的图片缓存控件(https://gith ...
- 学习WPF——使用Font-Awesome图标字体(一)
一.运行效果图 二.图标字体文件下载 http://fontawesome.dashgame.com/(这个网址可以下载图标字体文件) http://www.fontawesome.com.cn/(这 ...
- uboot处理dtb
目录 uboot处理dtb 传递参数给内核 dtb 地址选择 dtb修改 移植fdt title: uboot处理dtb date: 2019/4/28 17:18:19 toc: true --- ...
- Jedis 操作 Redis 工具类
配置类 pom.xml pom.xml 里配置依赖 <dependency> <groupId>redis.clients</groupId> <artifa ...
- Autowired byType 与 byName 策略
@Autowired是spring的注解,默认使用的是byType的方式向Bean里面注入相应的Bean.例如: @Autowiredprivate UserService userService;这 ...
- js禁止鼠标右键功能
1.禁止指定元素 document.getElementById("active-intro").oncontextmenu = function () { event.retur ...
- postman自定义函数实现 时间函数
一:主要内容 postman环境变量方式封装格式化日期函数:yyyy-MM-dd HH:mm:ss postman利用moment模块实现格式化日期函数:yyyy-MM-dd HH:mm:ss 二:p ...
- k8s集群之上游dns--dnsmasq,统一管理kubernetes的dns解析
1.概述 首先部署好kubernetes集群并采用Coredns进行解析,这样集群内部的服务都能通过内部域名进行访问.但是集群内部的coredns与物理机的dns解析不完全统一,coredns不能解析 ...