反射机制的应用
来源:互联网 发布:淘宝上刘老中医可靠吗 编辑:程序博客网 时间:2024/05/21 07:47
前两天朋友(小许)问我,为什么要用反射?反射都用哪些地方应用到,还有就是Struts框架用反射是不是多此一举,所以今天我腾出时间,就这几个问题做个系统的回答。
首先先说说反射,程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性”–《来自百度的解释》
上面已经解释了反射,下面我就说说他在具体框架或开发中的应用。
大部分的框架都用到了反射机制,比如Struts1、2,Spring,Nspring,Hibernate等等,那就先说说我朋友比较关心的struts为什么用反射机制;
struts中反射的应用
根据下图可以看到,期主要原因就是应用反射将提交过来的请求经过(第三步)进行反射后找到对应的业务(方法)步骤如下:
(1)StrutsPrepareAndExecuteFilter会去创建Action实例 ——假如我们请求abc.action,StrutsPrepareAndExecuteFilter会搜索struts.xml文件中的name为abc的Action配置,根据class属性使用反射来创建Action实例(2)调用 “Map <String, String> paramMap = request.getParameterMap();"//返回所有请求参数,这就是为什么开发Struts2的Action**无需与Servlet耦合** 使用循环for(String paramName: paramMap.keySet()) { //得到请求参数名对应的setter方法 Method setter = actionClazz.getMethod("set" + paramName.substring(0,1).toUpperCase() + paramName.substring(1), string.class); //得到请求参数对应的值 String paramValue = paramMap.get(paramName); //以Action实例为调用者,调用setter方法,把请求参数值作为参数值传入,,这就是为什么开发Struts2的Action无需与Servlet耦合 setter.invoke(actionInst, paramValue); }(3)再次通过反射来调用method属性所指定的方法,返回一个字符串
优点: 这样就可以降低耦合度、开发模块化、提高复用性,全局结果与声明式异常 等优点。
说白了就是你前端该干你们的活干你们的活,我后台该写什么写什么,两不耽误,回头只需要在配载文件上一配,通过反射前后一结合,程序就成了。谁也不依赖谁(低耦合)后面给你好好说说。
反射在IOC中的应用
SPRING(JAVA)、NSPRING(.NET)、AUTOFAC(.NET)的核心就是IOC,下面就重点说下IOC(控制反转)
IOC:
为了降低程序的耦合度我们会相应的引用IOC框架,IOC的核心实现机制就是反射。
估计初学者(小许)够呛能理解,下面具体的解释一下:
1、控制反转:
对于你来说,平时写代码,“一段代码会完全控制了程序的流程”,因为我们习惯于用new关键字来创建对象,再通过对象来调用它的方法。对于我们来说,这是再正常不过的了,可是如果此时我们的需求发生了一点改变,我们就不得不修改源代码,这就是我们常讲的“硬编码(就是编码一点也不活,面对好的产品设计以及好的产品经理来说可能修改少点,但是有2b的就苦逼了)”,而修改源代码是程序设计的大忌,这违反了程序设计的“开闭原则”,即对扩展是开放的,对修改是关闭的。
举个例子,当我们写完代码时,我们的程序只能执行强哥吃东西,可是如果此时需求变了我们要李屁股吃东西不是强哥了,是不是我们的代码要变了呢,回头2b产品经理又抽风了,要林哥吃……。此时是不是很抓狂,所以我们会引入了配置文件机制,我们事先在配置文件中已经配置好了该是谁吃东西,等到程序运行时,程序会读取配置文件中的值通过反射机制创建一个我们需要的对象,再调用它的eat方法就ok了。这样看来,我们程序的执行流程控制权是不是转交给了配置文件了(只要改配置文件就行,爱谁吃谁吃),而程序代码自己却成了被控制的对象,这就是实现了“控制反转”了。(不知道明白没。。。不明白再电联)
2、依赖注入:(降低程序耦合度的核心方法)
在讲依赖注入之前,我想先讲一讲依赖注入的三种实现方式。
(1)构造注入, 是通过构造器方法注入实例变量public class 强哥 {public void 吃(){ //•••• }}public class People { private 强哥 小强; public People(强哥 小强) {//构造注入 this.小强=小强; } public void eat(){ 小强.吃(); }} (2)设值注入,是通过setter方法注入实例变量public class People { private 强哥 小强; public void set强哥(强哥 小强) {//设置注入 this.小强= 小强; } public void 吃(){ 小强.吃(); }} (3)接口注入,是通过接口方法注入实例变量(最常用的)public interface I强哥 { public void 吃();}public class 强哥:I强哥 {public void 吃(){ 。。。 }}public class People {public void 吃(I强哥 I小强){//接口注入 I小强.吃(); }}
那么问题来了:依赖注入有毛用呢?
这样既没降低耦合,也没降低程序的复杂度(到底有毛用),可是当我们考虑到配置文件时,我们就豁然开朗了,不管是哪种注入方法,目的都是给我们的程序传入一个实例变量。而这个实例变量我们可以事先在配置文件中配置,当程序运行时就可以读取配置文件,通过反射机制来创建所需的对象了,如果此时我们的需求发生了变化,我们也只需改一下配置文件就o了。这里有些人可能会认为这也修改了文件呀,为什么修改配置文件就可以了呢。呵呵,其实配置文件是不需要编译的,我们可以随时修改配置文件,而不需要通过更改一行源代码的方法就实现了程序流程的控制。这就是ICO一个很伟大的功能。
3、IOC容器
使用IOC后,我们不需要自己去创建某个类的实例,而由IOC容器去创建,当我们需要使用某个对象时,直接到容器中去获取就可以了。现在已经有许多非常优秀的IOC容器,比如spring等。
反射在其他地方的应用
就拿最近项目的几个例子给你分享下吧。
例子1:
问题:当你的表单项很多时,而且每个控件的内容都需要保存你会怎么办?哈哈,如果一个一个写会累死的而且程序的可维护性会降低,所以我选择用反射,将控件的名称在命名的时候与相对应的类名相同,回头一个循环再加几个判断就搞定了,给你找个代码:
以前我们是这样的…有种累傻小子的赶脚没?
News news = new News(); news.Id = int.Parse(Request.Form["Id"]); news.Category = int.Parse(Request.Form["Category"]); news.Title = Request.Form["Title"]; ...N多行 news.CreateTime = DateTime.Parse(Request.Form["CreateTime"]);
用反射之后是这样的
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public static class HenqPost<T> where T: new()//new()为泛型约束,约束类型T必须具有无参的构造函数 { /// <summary> /// 为Model赋值 /// </summary> /// <typeparam name="T">Model</typeparam> /// <param name="t">model</param> /// <param name="form">Request</param> /// <returns></returns> public static int GetPost<T>(ref T t, NameValueCollection form) { int va=0; Type type = t.GetType();//获取类型 PropertyInfo[] pi=type.GetProperties();//获取属性集合 foreach( PropertyInfo p in pi ) { if (form[p.Name] != null) { try { p.SetValue(t, Convert.ChangeType(form[p.Name], p.PropertyType), null);//为属性赋值,并转换键值的类型为该属性的类型 va++;//记录赋值成功的属性数 } catch { } } } return va; } }
简单的几行,解决了所有表单向对象的赋值问题。同理对象向表单赋值也可以模仿着写下。
例子2:
与例子1类似,这次我们是从数据库里读数据之后封装成Model
以前是这样的
bll_tydModel model = new bll_tydModel(); DataSet ds = InitHelperDAL.dbHelper.GetDataSet(strSql.ToString(), parameters); if (ds.Tables[0].Rows.Count > 0) { if (ds.Tables[0].Rows[0]["no"].ToString() != "") { model.no = int.Parse(ds.Tables[0].Rows[0]["no"].ToString()); } model.ydcfgs = ds.Tables[0].Rows[0]["ydcfgs"].ToString(); model.ydbc = ds.Tables[0].Rows[0]["ydbc"].ToString(); model.kczt = ds.Tables[0].Rows[0]["kczt"].ToString(); ...//以下N行代码
虽然有动软、codesmith等代码生成工具但是维护起来还是巨费劲的。
下面看看用反射是什么样的
public List<T> FillModel(DataTable dt) { if (dt == null || dt.Rows.Count == 0) { return null; } List<T> modelList = new List<T>(); foreach (DataRow dr in dt.Rows) { T model = new T(); foreach (PropertyInfo propertyInfo in propertys) { SetValue(propertyInfo, dr, model); } modelList.Add(model); } return modelList; } private void SetValue(PropertyInfo p, DataRow dr, T model) { if (!dr.Table.Columns.Contains(p.Name)) { return; } if (dr[p.Name] == DBNull.Value) { return; } string value = string.Empty; DateTime dt; int i; double d; float f; long l; switch (p.PropertyType.Name) { case "String": value = dr[p.Name].ToString(); p.SetValue(model, value, null); break; case "DateTime": value = dr[p.Name].ToString(); if (value.Trim() == "" || !DateTime.TryParse(value, out dt)) { break; } p.SetValue(model, dt, null); break; case "Int32": value = dr[p.Name].ToString(); if (value.Trim() == "" || !int.TryParse(value, out i)) { break; } p.SetValue(model, i, null); break; case "Int64": value = dr[p.Name].ToString(); if (value.Trim() == "" || !long.TryParse(value, out l)) { break; } p.SetValue(model, l, null); break; case "Double": value = dr[p.Name].ToString(); if (value.Trim() == "" || !double.TryParse(value, out d)) { break; } p.SetValue(model, d, null); break; case "Single": value = dr[p.Name].ToString(); if (value.Trim() == "" || !float.TryParse(value, out f)) { break; } p.SetValue(model, f, null); break; case "Byte[]": p.SetValue(model, dr[p.Name], null); break; default: break; } }
代码是这样的 。。。是泛型方法适用于各种类型,()hibernate核心的东西就是这个。(看不懂电联)
例子3
动态创建实例
问题:估计你们用到的类都是已知的,那么问题来了,当你用到了类在设计的时候是不确定的(如动态表的构造-不懂电联哈)属性不定、属性值类型不定。。。怎么办?
遇到这种情况就是反射机制发挥作用的时候了。
java动态创建类,写得很详细,有空可以看看~!
http://www.tuicool.com/articles/7BVnyau
.net 动态创建类写得不如上面的。。。
http://www.cnblogs.com/lichdr/archive/2004/11/02/59620.html
在工作中目前就遇到这些,希望对你有点帮助~!不懂的再联系
- 反射机制的应用
- 反射机制的应用
- 反射机制的应用
- JAVA反射机制的应用
- java反射机制的应用
- 反射机制的应用举例
- java反射机制的应用
- java 反射机制的应用
- 反射机制的应用实例
- java反射机制的应用
- java反射机制的常见应用
- 反射机制的理解与应用
- JAVA反射机制的简单应用
- java 反射机制的一些应用
- javascript中的反射机制的应用
- java 反射机制的研究与应用
- JAVA反射机制的简单应用
- JAVA中反射机制的应用
- 领域驱动设计之领域模型
- 简单Properties属性读取
- 6.2.1_描边与填充绘制器
- Spring:IOC—控制反转(2)
- hdu1249 三角形
- 反射机制的应用
- 6.2.1_描边与填充绘制器
- Git时间 版本控制工具 2017-05-27
- Laravel-lumen 配置JWT
- 【AngularJS】过滤器——currency 过滤器
- redis:Unable to validate object ;Could not get a resource from the pool;(error) MISCONF Redis is con
- Ubuntu切换到root用户
- JavaScript笔记
- 326. Power of Three