- 浏览: 85801 次
- 性别:
- 来自: 杭州
-
最新评论
-
xvshell:
写的通俗易懂
Spring温故知新(九)Spring自动代理 (系列第一部分完结篇) -
雅礼彭培:
写的好,理解了
Spring温故知新(九)Spring自动代理 (系列第一部分完结篇) -
gongjinglin1989:
大神,能指教1,2吗?我想请教几个问题,我们现在有做好得web ...
Hybrid App的实际运用项目 -
bolide74:
jacking124 写道恭喜你呀!!3Q
新年展望 -
bolide74:
zlex 写道不要泄密呀轩?我有hold住啊,没算泄密吧……
新年展望
在介绍Spring的IoC容器之前,我首先要给大家介绍一下我刚刚花了仅仅10分钟就写出来的一个用HashMap而不是用XML来配置的IoC容器,然后剖析这段代码,彻底的撕碎初学者对于IoC概念的恐惧感(好像有点夸张了,哈哈!)
首先还是亲切的Robot类:
为了解释,这个类只有一个属性。使用了set注入
这里我把类名叫做RobotBean,这是为了提前让大家知道Bean这么一个东西,告诉大家这个就是一个Bean,而关于Bean到底代表着什么意思,那么下回我就会介绍了。
下面就是简易IoC容器的代码了:
然后是实现类的应用代码:
这时候大家可以用这一段实现类代码和最初的第一篇HelloWorld的代码比较一下,是不是特别神似?http://bolide74.iteye.com/blog/993248只不过Spring的HelloWorld在实例化ApplicationContext这个IoC容器的时候还需要传入一个XML配置文件的路径,而我这里直接省略了。
这是为什么呢?那是因为我没有用XML来配置IoC容器,而是直接在IoC容器里建了一个HashMap来当作配置文件,一样能起到简单的配置功能。
这个HashMap结构很简单,Key就是RobotBean的ID,它可以是任意的字符串,不需要跟RobotBean的类名相关;而Value就是RobotBean的完整类名了,包含了RobotBean的包名和类名,这个就不能乱写了哈!
当然以后如果你又做了一个PeopleBean想要把它也加进这个IoC容器里来管理,那也是同理,新建一个HashMap配置容器
那么接下来就是要介绍IoC容器的真正核心所在了,如何根据这个“配置容器”来获取到一个实例:getBean()!
其实要是清楚JAVA的反射机制的同学,不用我介绍就直接明白了,但是如果不清楚什么叫反射的同学,我这里用最通俗但是可以不太准确的说法来介绍:反射,就是根据一个类的完整类名(包名+类名),来把这个类实例化。注意,实例化出来的类型是一个类,叫做Class类类型。也就是是说Robot机器人不再是一个称呼,一个代号,而是切切实实存在的看的见摸的着一个种类(要还是不能理解,你就暂时把它想像成机器人工厂类的一个实例吧...)。
然后获取到了这么一个实例类以后,就可以直接调用一个newInstance()方法,也就是让这个实例类自动的产生一个这个类的实例对象给我们,就像是机器人工厂实例生产出了一个机器人。
这时候我们可以看到,getBean这个方法的返回类型是Object,也就是一个超类型。java也好C#也好都有一个特性,就是所有的类都是Object的子类,所以Object可以代表任何类。
这样一来的话,在应用代码中调用getBean()方法的时候,只要把返回类型强制转换为调用getBean方法的引用对象的类型就可以了。
以上内容,就基本上剖析了IoC的实现原理,当然真正Spring的IoC框架功能更强大,我这个在依赖注入的时候还是直接写死的类型,其实还可以自动判断的。但对于描述IoC容器实现原理没太大意义,这里就省略了。
最后我要告诉大家的是,以上内容纯属猜测,如有雷同那真是太巧啦!
我其实没看过Spring的源码哈,都是猜的,我想应该八九不离十,万一错了,千万别回头来找我算账,概不负责哦~
下一篇:Spring温故知新(五)Spring的Bean和IoC 容器 http://bolide74.iteye.com/blog/1004086
上一篇:Spring温故知新(三)singleton单例模式 http://bolide74.iteye.com/blog/1001630
嗯,会有这个疑问,可能是由于你还对Spring的依赖注入还不够了解。事实上如果你从第二章开始看起的话你就会发现,"在客户端测试类中获得bean实例后用户自己设置的"是msg这个值,也就是Speak方法的形参。
而name值是RobotBean类的一个成员属性,而不是方法的形参,因此是需要在获取RobotBean的实例之前就要在配置文件中注入,这样才能达到控制和管理实例的作用。
可以参照与前面几章的简单工厂方法来加强理解含义,如果不事先注入这个成员属性,那所谓的简单工厂方法也就没有了它存在的意义,而IoC的最大优势也就体现不出来了。
所以事实上,"我们在xml里只配置了bean的id和class,并没有把bean中属性的值也配进去"这个理解是错误的,xml里配置bean的id和class只是基础作用,更大的作用就是为了注入bean的属性
是的,不过我的初衷只为了解释原理而不是写一个成熟的IoC容器,因此尽可能的把与主题无关的代码给省略掉了,希望那些准备写自己的成熟容器的同学别学这个示例啊!
其实咱做编程的一向都是会的不难,难的就是不会,只要明白了原理以后就都很简单了
哈哈,看LZ很牛逼,看了几篇文章,嗯,非常不错,记得你说你学java是直接从spring开始扣得,我很佩服,我本来是搞java的后来干了半年,现在外包,干的乱七八糟,想复习无处下手,索性看看你得文章,很不错,像做了至少3年的人写的。得多学习啊
其实也是因为我有C#的基础,要不然也啃不下来啊
哈哈,看LZ很牛逼,看了几篇文章,嗯,非常不错,记得你说你学java是直接从spring开始扣得,我很佩服,我本来是搞java的后来干了半年,现在外包,干的乱七八糟,想复习无处下手,索性看看你得文章,很不错,像做了至少3年的人写的。得多学习啊
引用
以下示例只为了解释原理而不是写一个成熟的IoC容器,因此尽可能的把与主题无关的代码给省略掉了,希望那些准备写自己的成熟容器的同学别学这个示例
首先还是亲切的Robot类:
package com.iteye.bolide74.action; public class RobotBean { public String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void Speak(String msg) { System.out.println(msg + ",我是" + this.name); } }
为了解释,这个类只有一个属性。使用了set注入
这里我把类名叫做RobotBean,这是为了提前让大家知道Bean这么一个东西,告诉大家这个就是一个Bean,而关于Bean到底代表着什么意思,那么下回我就会介绍了。
下面就是简易IoC容器的代码了:
package com.iteye.bolide74.action; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; public class MySpringIoC { public HashMap<String, HashMap<String, Object>> configLikeXML = new HashMap<String, HashMap<String, Object>>(); public MySpringIoC() { HashMap<String, Object> robotBeanConfig = new HashMap<String, Object>(); robotBeanConfig.put("class", "com.iteye.bolide74.action.RobotBean"); robotBeanConfig.put("name", "Robot1"); configLikeXML.put("Robot", robotBeanConfig); } public Object getBean(String beanID) { // 获取hashMap配置内容 HashMap<String, Object> beanConfig = this.configLikeXML.get(beanID); // 获取完整类名 String className = (String) beanConfig.get("class"); Class<?> bean = null; try { // 获取类类型实例 bean = Class.forName(className); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } Object instance = null; try { // 获取这个类的一个实例 instance = bean.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } for (Field field : bean.getDeclaredFields()) { // 获取属性名 String fieldName = field.getName(); // 在hashMap获取属性要注入的值(这里为了方便把类型写死了) String fieldValue = (String) beanConfig.get(fieldName); Method method = null; try { // 获取到这个属性的set方法(这里为了方便把类型写死了) method = bean.getDeclaredMethod( "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), new Class[] { String.class }); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } try { // 调用set方法 method.invoke(instance, new Object[] { fieldValue }); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } return instance; } }
然后是实现类的应用代码:
package com.iteye.bolide74.tester; import com.iteye.bolide74.action.MySpringIoC; import com.iteye.bolide74.action.RobotBean; public class MySpringIoCTester { public static void main(String[] args) { MySpringIoC beanFactory = new MySpringIoC(); RobotBean robotBean = (RobotBean) beanFactory.getBean("Robot"); robotBean.Speak("Hello,world!"); } }
这时候大家可以用这一段实现类代码和最初的第一篇HelloWorld的代码比较一下,是不是特别神似?http://bolide74.iteye.com/blog/993248只不过Spring的HelloWorld在实例化ApplicationContext这个IoC容器的时候还需要传入一个XML配置文件的路径,而我这里直接省略了。
这是为什么呢?那是因为我没有用XML来配置IoC容器,而是直接在IoC容器里建了一个HashMap来当作配置文件,一样能起到简单的配置功能。
这个HashMap结构很简单,Key就是RobotBean的ID,它可以是任意的字符串,不需要跟RobotBean的类名相关;而Value就是RobotBean的完整类名了,包含了RobotBean的包名和类名,这个就不能乱写了哈!
当然以后如果你又做了一个PeopleBean想要把它也加进这个IoC容器里来管理,那也是同理,新建一个HashMap配置容器
那么接下来就是要介绍IoC容器的真正核心所在了,如何根据这个“配置容器”来获取到一个实例:getBean()!
其实要是清楚JAVA的反射机制的同学,不用我介绍就直接明白了,但是如果不清楚什么叫反射的同学,我这里用最通俗但是可以不太准确的说法来介绍:反射,就是根据一个类的完整类名(包名+类名),来把这个类实例化。注意,实例化出来的类型是一个类,叫做Class类类型。也就是是说Robot机器人不再是一个称呼,一个代号,而是切切实实存在的看的见摸的着一个种类(要还是不能理解,你就暂时把它想像成机器人工厂类的一个实例吧...)。
然后获取到了这么一个实例类以后,就可以直接调用一个newInstance()方法,也就是让这个实例类自动的产生一个这个类的实例对象给我们,就像是机器人工厂实例生产出了一个机器人。
这时候我们可以看到,getBean这个方法的返回类型是Object,也就是一个超类型。java也好C#也好都有一个特性,就是所有的类都是Object的子类,所以Object可以代表任何类。
这样一来的话,在应用代码中调用getBean()方法的时候,只要把返回类型强制转换为调用getBean方法的引用对象的类型就可以了。
以上内容,就基本上剖析了IoC的实现原理,当然真正Spring的IoC框架功能更强大,我这个在依赖注入的时候还是直接写死的类型,其实还可以自动判断的。但对于描述IoC容器实现原理没太大意义,这里就省略了。
最后我要告诉大家的是,以上内容纯属猜测,如有雷同那真是太巧啦!
我其实没看过Spring的源码哈,都是猜的,我想应该八九不离十,万一错了,千万别回头来找我算账,概不负责哦~

下一篇:Spring温故知新(五)Spring的Bean和IoC 容器 http://bolide74.iteye.com/blog/1004086
上一篇:Spring温故知新(三)singleton单例模式 http://bolide74.iteye.com/blog/1001630
评论
10 楼
bolide74
2011-05-10
yuanyu5237 写道
楼主,不好意思,我有点不明白,为什么要在robotBeanConfig.put("name", "Robot1"); 这里传入RobotBean的name值,我们在xml里只配置了bean的id和class,并没有把bean中属性的值也配进去,属性值(name的值)应该是再客户端测试类中获得了bean的实例后,用户自己设置的吧,希望楼主能解释下,谢谢
写的很不错,加你关注了
写的很不错,加你关注了
嗯,会有这个疑问,可能是由于你还对Spring的依赖注入还不够了解。事实上如果你从第二章开始看起的话你就会发现,"在客户端测试类中获得bean实例后用户自己设置的"是msg这个值,也就是Speak方法的形参。
而name值是RobotBean类的一个成员属性,而不是方法的形参,因此是需要在获取RobotBean的实例之前就要在配置文件中注入,这样才能达到控制和管理实例的作用。
可以参照与前面几章的简单工厂方法来加强理解含义,如果不事先注入这个成员属性,那所谓的简单工厂方法也就没有了它存在的意义,而IoC的最大优势也就体现不出来了。
所以事实上,"我们在xml里只配置了bean的id和class,并没有把bean中属性的值也配进去"这个理解是错误的,xml里配置bean的id和class只是基础作用,更大的作用就是为了注入bean的属性
9 楼
yuanyu5237
2011-05-10
楼主,不好意思,我有点不明白,为什么要在robotBeanConfig.put("name", "Robot1"); 这里传入RobotBean的name值,我们在xml里只配置了bean的id和class,并没有把bean中属性的值也配进去,属性值(name的值)应该是再客户端测试类中获得了bean的实例后,用户自己设置的吧,希望楼主能解释下,谢谢
写的很不错,加你关注了
写的很不错,加你关注了
8 楼
2xusi
2011-05-05
挺 好 的
7 楼
bolide74
2011-04-29
C.T 写道
你的Map容器如果是这样处理的话,应该至少加多一个方法,可以将你的映射放入你的
里面的robotBeanConfig中吧。这样方便点。
HashMap<String, Object> robotBeanConfig = new HashMap<String, Object>();
里面的robotBeanConfig中吧。这样方便点。
是的,不过我的初衷只为了解释原理而不是写一个成熟的IoC容器,因此尽可能的把与主题无关的代码给省略掉了,希望那些准备写自己的成熟容器的同学别学这个示例啊!
6 楼
C.T
2011-04-29
你的Map容器如果是这样处理的话,应该至少加多一个方法,可以将你的映射放入你的
里面的robotBeanConfig中吧。这样方便点。
HashMap<String, Object> robotBeanConfig = new HashMap<String, Object>();
里面的robotBeanConfig中吧。这样方便点。
5 楼
bolide74
2011-04-28
爪哇岛岛主 写道
无非就是一个填值的问题,我大二的时候写了一个很垃圾的,不过现在都无所谓写了,很多框架做的非常出色。。。
其实咱做编程的一向都是会的不难,难的就是不会,只要明白了原理以后就都很简单了
4 楼
bolide74
2011-04-28
竹隐江南 写道
bolide74 写道
消灭0回复! 莫非现在都只对单纯的设计模式感兴趣么。。。
哈哈,看LZ很牛逼,看了几篇文章,嗯,非常不错,记得你说你学java是直接从spring开始扣得,我很佩服,我本来是搞java的后来干了半年,现在外包,干的乱七八糟,想复习无处下手,索性看看你得文章,很不错,像做了至少3年的人写的。得多学习啊
其实也是因为我有C#的基础,要不然也啃不下来啊
3 楼
爪哇岛岛主
2011-04-28
无非就是一个填值的问题,我大二的时候写了一个很垃圾的,不过现在都无所谓写了,很多框架做的非常出色。。。
package util; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import pojo.Admin; public class FillPojo<T> { static Admin admin = null; @SuppressWarnings("unchecked") public T fillPojo(Class<T> obj,Map<String,Object> mapData) throws Exception{ Map.Entry<String, Object> param = null; Iterator<Map.Entry<String, Object>> it = mapData.entrySet().iterator(); T pojo = null; Class<?> myClass = null; String propertyName = null; Object propertyValue = null; Field field = null; Method method = null; StringBuffer methodName = null; myClass = Class.forName(obj.getName()); /** * 获取POJO实例 */ pojo = (T) myClass.newInstance(); while(it.hasNext()){ param = (Entry<String, Object>)it.next(); /** * 获取属性的名称和值 */ propertyName = param.getKey(); propertyValue = param.getValue(); /** * 获取属性的setter方法名称 */ methodName = new StringBuffer(); methodName.append("set"); methodName.append(propertyName.substring(0, 1).toUpperCase()); methodName.append(propertyName.substring(1)); field = myClass.getDeclaredField(propertyName); method = myClass.getMethod(methodName.toString(),field.getType()); method.invoke(pojo,propertyValue); } return pojo; } }
2 楼
竹隐江南
2011-04-28
bolide74 写道
消灭0回复! 莫非现在都只对单纯的设计模式感兴趣么。。。
哈哈,看LZ很牛逼,看了几篇文章,嗯,非常不错,记得你说你学java是直接从spring开始扣得,我很佩服,我本来是搞java的后来干了半年,现在外包,干的乱七八糟,想复习无处下手,索性看看你得文章,很不错,像做了至少3年的人写的。得多学习啊
1 楼
bolide74
2011-04-14
消灭0回复! 莫非现在都只对单纯的设计模式感兴趣么。。。
发表评论
-
Spring温故知新:WEB篇(二)Hello,World!
2011-08-29 15:22 3689在准备写代码之前,我们首先得把下列必备的库导入项目: spri ... -
Spring温故知新:WEB篇(一) 准备工作
2011-08-16 12:42 1621最近一直都忙着做项目还有一些私人的事情,都没时间更新,今天抽空 ... -
《Spring温故知新》第一部分<Spring基础> 电子书制作完毕,提供下载
2011-05-19 14:03 1968由于有人需要,所以刚刚把之前的Spring基础部分制作成了电子 ... -
Spring温故知新(九)Spring自动代理 (系列第一部分完结篇)
2011-05-19 10:29 3485这是《Spring温故知新》系列的第一部基础部分的最后一篇,简 ... -
Spring温故知新(八)静态切入点和CGLIB代理,更智能、更方便!
2011-05-18 10:17 2735前面一章我们利用了Spring的AOP框架实现了WALL-E自 ... -
Spring温故知新(七)Advice通知的5种类型
2011-05-10 12:52 5751这一章内容比较简单,就是大致的了解一下Spring的AOP框架 ... -
Spring温故知新(六)AOP面向切面编程 <3>
2011-05-09 13:19 2419我们开发小组跟网易的合作项目终于上线了,我自己的一些私人琐事也 ... -
Spring温故知新(六)AOP面向切面编程 <2>
2011-04-19 11:47 2648上一章我们讲到了用代 ... -
Spring温故知新(六)AOP面向切面编程 <1>
2011-04-18 16:55 2917这一章我们将开始剖析Spring框架最为重要的AOP(Aspe ... -
AbstractFactory 抽象工厂模式(已补完)
2011-04-13 16:54 3356为了跟别人的有所区别,我这里直接就用接口来实现抽象工厂了,毕竟 ... -
Spring温故知新(三)singleton单例模式
2011-04-13 14:29 7116本来今天打算介绍一下Spring的IoC容器,但是开了一早上的 ... -
Spring温故知新(二) IoC控制反转与DI依赖注入(修正1)
2011-04-12 11:20 6387学习Spring,所有教程都是从IoC和DI开始的,但 ... -
Spring温故知新(一)Hello,World!
2011-04-08 18:13 3154这是我的JAVA学习笔记的第一篇,由于本身就不是写给外人看的, ...
相关推荐
- 电子书《Spring温故知新》由ITeye社区提供,强调了开发者社区在知识分享和技术交流中的作用。 - 作者bolide74通过撰写博客文章,记录和分享学习经验,并邀请社区成员进行讨论和修正。 11. 学习方法与经验分享:...
Spring的核心组件包括IoC容器、AOP、MVC等,用于简化企业级应用开发。 18. **什么是Maven?** Maven是一个项目管理和综合工具,它通过配置文件管理项目的构建、依赖关系和文档生成。 19. **Eclipse和IntelliJ ...
少儿编程scratch项目源代码文件案例素材-直升机飞行.zip
wanjunshe_Python-Tensorflow_12888_1745868924470
健康监测_Android开发_BLE蓝牙通信_心率数据采集与存储_基于小米手环2的实时心率监测应用_支持后台长时间运行的心率记录工具_可导出SQLite数据库的心率数据分析系统_适
少儿编程scratch项目源代码文件案例素材-种花模拟器.zip
嵌入式系统开发_FreeRTOS实时操作系统_STM32F103C8T6微控制器_OLED显示屏_DHT11温湿度传感器_多任务调度_多级菜单设计_万年历算法_电子闹钟功能_参数配
基于python实现的粒子群的VRP(车辆配送路径规划)问题建模求解+源码+项目文档+算法解析,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 算法设计的关键在于如何向表现较好的个体学习,标准粒子群算法引入惯性因子w、自我认知因子c1、社会认知因子c2分别作为自身、当代最优解和历史最优解的权重,指导粒子速度和位置的更新,这在求解函数极值问题时比较容易实现,而在VRP问题上,速度位置的更新则难以直接采用加权的方式进行,一个常见的方法是采用基于遗传算法交叉算子的混合型粒子群算法进行求解,这里采用顺序交叉算子,对惯性因子w、自我认知因子c1、社会认知因子c2则以w/(w+c1+c2),c1/(w+c1+c2),c2/(w+c1+c2)的概率接受粒子本身、当前最优解、全局最优解交叉的父代之一(即按概率选择其中一个作为父代,不加权)。 算法设计的关键在于如何向表现较好的个体学习,标准粒子群算法引入惯性因子w、自我认知因子c1、社会认知因子c2分别作为自身、当代最优解和历史最优解的权重,指导粒子速度和位置的更新,这在求解函数极值问题时比较容易实现,而在VRP问题上,速度位置的更新则难以直接采用加权的方式进行,一个常见的方法是采用基于遗传算法交叉算子的混合型粒子群算法进行求解,这里采用顺序交叉算子,对惯性因子w、自我认知因子c1、社会认知因子c2则以w/(w+c1+c2),c1/(w+c1+c2),c2/(w+c1+c2)的概率接受粒子本身、当前最优解、全局最优解交叉的父代之一(即按概率选择其中一个作为父代,不加权)。
scratch少儿编程逻辑思维游戏源码-猫猫粉碎.zip
scratch少儿编程逻辑思维游戏源码-蓝胡子.zip
scratch少儿编程逻辑思维游戏源码-美食大亨.zip
scratch少儿编程逻辑思维游戏源码-洛克人.zip
scratch少儿编程逻辑思维游戏源码-龙冲刺.zip
思幻个人引导页V2.2版本11月29日更新.zip
scratch少儿编程逻辑思维游戏源码-骑士风斩法.zip
移动应用开发_H5CSS3ionicng-cordovaMVVM模式_基于HTML5和CSS3技术实现多页面布局ionic指令数据绑定ui-route单页跳转调用手机
少儿编程scratch项目源代码文件案例素材-植物大战僵尸创造版 Ver. 1.0.3.zip
scratch少儿编程逻辑思维游戏源码-日落(2).zip
动态星空背景个人主页(带后台).zip
scratch少儿编程逻辑思维游戏源码-迷雾森林:诞生 3.2 起源觉醒.zip