java反射+代理及其在框架中的使用情况

反射(reflect)

反射是什么?官方解释是能够分析类能力的程序称为反射,也就是说反射在解析时可以获取类的信息。为什么会有反射这个概念呢?这是因为一个类当你无法获取它的实例,却又想对这个类的实例进行管理时就需要反射来实现。下面我们一步步来对反射进行深入了解:我们知道和反射有关的类主要有5中:
  • Class类(对应类的结构信息)
  • Field类(对应类的域)
  • Method类(对应类成员方法)
  • Constructor(对应类的构造函数)
  • Modifier(对应类及类中域,方法,构造函数的权限)
Class类
注意这个Class并不是常见的类声明时用到的class,而是Class类型的实例,它保存的是某个类的所有属性(即信息)。
获取类信息的方式有以下三种:
  • Object类中的getClass()方法返回Class类型的实例:
Student s ;
Class c = s.getClass();
  • 调用静态方法forName获取类名对应的Class对象:
String s = "java.util.Random";
Class c = Class.forName( s );
  • 类型.class代表匹配的类对象
Class c = Random.class;

注意:一个Class对象表示的是一个类型,而这个类型不一定是一个类,例如int表示一个类,但int.class是一个Class类型的对象。

重点来了:通过以上三种方式我们可以获取类信息,而通过类信息我们可以创建一个对象,像:

String s = "java.util.Random";
Class c = Class.forName( s );//获取类信息
Object o = c.newInstance();//创建对象
Field类
Field类有一个getType()方法,用来返回描述域所属类型的Class对象。
Class类可以通过getFields()方法来返回public域,其中包括其父类的public域;
Class也可以通过getDeclareFields()方法来获取类中声明的全部域(但这种方法不会获取父类的域)
Method类和Constructor类
Method类和Constructor类都有能够报告参数类型的方法,另外Method类有一个可以报告返回类型的方法。
Modifier类
上面三个类(Field类,Method类,Constructor类)都有一个叫getModifiers()的方法,它返回的是一个整形,而Modifier类有一个静态方法可以分析出这些整形对应的修饰符是什么。可以参考下下面代码:
String s = "java.util.Random";
Class c = Class.forName( s );//获取类信息
String modifier = Modifier.toString(c.getModifiers());//c.getModifiers()返回的就是整形,toString方法将对应的修饰符打印出来

另外Field类,Method类,constructor类都有像getName()(获取域名,方法名,构造名),getModifier()(获取权限),getReturnType()(获取一个描述返回类型的Class对象),getParameterTypes()(返回描述参数类型的Class对象数组);还有就是当你获取的域或方法是私有的时,你得将它的权限通过setAccessible设置为可访问的。

代理(proxy)

利用代理可以在运行时创建一个实现了一组给定接口的新类。代理只有在编译时无法确定需要实现哪个接口才使用到。
创建代理对象
要创建代理对象,需要使用Proxy类newProxyInstance方法,三个参数:类加载器(null表示默认的类加载器),Class对象数组(对应所需要实现的接口),调用处理器。
代理就是执行你反射的方法,而不需要你手动添加方法。
需要注意的是代理中有个很重要的方法:invoke():
Object invoke (Object proxy,Method method,Object[] args) //proxy代表代理对象,method代表需要调用的方法,args代表方法所需的参数。
//这整个方法代表的含义就是代理对象调用方法时希望执行的动作。

单例模式

说到反射和代理,不能不了解一个名词:单例模式。什么是单例模式?单例模式就是只在map中创建一个对象,然后各种类去调用它。为什么反射和代理需要使用单例模式?因为如果每个类你都创建相同一个对象的话,会大大的消耗内存,而且没必要。但由于各个类都可以调用它,就会使得线程不安全(每个类对这个对象进行修改时产生的线程不安全),所以最好是对这个对象用final修饰。
像spring MVC中的注解@Service其实就是只创建了一个实例,其他的都是在调用同一个实例。这样大大节省了内存。

附加

上面已经堆反射和代理进行了一些讲解,我们在这对此进行一些扩展。
我们知道所有的框架都是通过反射+代理的方式来实现,像servlet,spring MVC之类的。在这我们以tomcat来实例讲解一波:

在这里插入图片描述

  1. tomcat时时监听端口,当有请求传向tomcat时,tomcat就将请求放入线程池消息队列中(因为不可能来多少消息就出创建多少线程,这样内存是吃不消的),
  2. 通过socket读取数据。
  3. http是字符串形式的,以换行符分隔,然后封装成HttpServletRequest和HttpServletResponse
  4. 分析url,通过在map中寻找servlet路径。map是以k-value的形式存储数据的:k:注解的servlet名,value:servlet名对应的servlet包路径。
  5. 执行反射。我们在上面讲过可以通过forName方法来获取类信息实例c,通过newInstance获取servlet实例。
  6. 提取请求方式(get或post),然后通过 Method m = c…getMethod(“doGet”);获取对应的请求方式方法。
  7. 最后通过invoke(servlet实例,m,入参)来代理执行一个未知servlet的实例方法。这里的入参就是前面封装的HttpServletRequest和HttpServletResponse。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值