`
bolide74
  • 浏览: 84818 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Spring温故知新(四)用HashMap写一个自己的Spring IoC简易容器吧!(改进一)

阅读更多
在介绍Spring的IoC容器之前,我首先要给大家介绍一下我刚刚花了仅仅10分钟就写出来的一个用HashMap而不是用XML来配置的IoC容器,然后剖析这段代码,彻底的撕碎初学者对于IoC概念的恐惧感(好像有点夸张了,哈哈!)

引用
以下示例只为了解释原理而不是写一个成熟的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
4
分享到:
评论
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容器如果是这样处理的话,应该至少加多一个方法,可以将你的映射放入你的

 HashMap<String, Object> robotBeanConfig = new HashMap<String, Object>(); 

里面的robotBeanConfig中吧。这样方便点。


是的,不过我的初衷只为了解释原理而不是写一个成熟的IoC容器,因此尽可能的把与主题无关的代码给省略掉了,希望那些准备写自己的成熟容器的同学别学这个示例啊!
6 楼 C.T 2011-04-29  
你的Map容器如果是这样处理的话,应该至少加多一个方法,可以将你的映射放入你的

 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_2021.7.14.zip

    这部分可能会介绍如何创建第一个Spring应用,包括引入Spring库,创建bean定义,以及如何启动和使用Spring容器。 综合来看,这份"spring_2021.7.14.zip"压缩包提供了Spring框架的初级到中级的学习资源,涵盖了从基础...

    Spring温故知新六AOP向切面程

    在Spring AOP中,我们可以创建一个`SpeakerProxy`代理类,它实现了`ISpeaker`接口,并持有真实对象的引用。在代理类的`say()`方法中,我们可以在调用真实对象的`say()`方法前后添加`getGift()`和`giveGift()`。 ```...

    Spring全家桶思维导图

    "Spring全家桶"这一术语,指的是Spring生态系统中的一系列相互关联的项目和技术,它们共同构成了一个全面的企业级应用开发解决方案。本思维导图包含了Spring的主要组成部分,对于初学者而言,它是一个了解Spring框架...

    springcloud视频学习6-2

    尚硅谷_SpringCloud_Rest微服务案例-部门服务消费者.avi》这个视频中,可能详细讲解了一个具体的部门服务消费者案例,涵盖了如何使用Restful API与服务提供者进行交互,以及如何利用SpringCloud的组件来实现微服务间...

    spring cloud + openshift

    spring cloud + openshift example

    spring cloud config

    Spring Cloud Config 是一个用于分布式系统配置管理的框架,它允许开发者在远程服务器上集中管理和版本化应用的配置,而不是在每个应用本地存储配置。这种方式在微服务架构中尤其有用,因为多个独立的服务需要共享和...

    Spring注解大全,常用,随时查看,学习

    常用的spring注解大全,适合新手学习、老手温故知新。读懂spring,平步青云。

    精通容器与容器云

    第二部分深入解读基于Docker的主流容器云技术,讲解了构建自己的容器云的方法,深入分析了3类Docker容器云技术的实现方法的设计思路,包括专注Docker容器编排与部署的容器云(Compose、Machine、Swarm、Fleet)、...

    java基础知识30个经典问答

    Spring的核心组件包括IoC容器、AOP、MVC等,用于简化企业级应用开发。 18. **什么是Maven?** Maven是一个项目管理和综合工具,它通过配置文件管理项目的构建、依赖关系和文档生成。 19. **Eclipse和IntelliJ ...

    JAVA课件 java 课件都有简易和复杂,我这个够简易的了。

    本课件集合旨在提供一个简单易懂的学习路径,适合初学者和有一定基础的开发者温故知新。 首先,Java的核心概念包括类、对象、封装、继承和多态。这些是理解Java编程的基础。类是对象的模板,它定义了一组特性和行为...

    jsp,servlet,filter温故知新

    在`FilterDemo`这个例子中,我们可以创建一个自定义的Filter,配置在web.xml中,指定其拦截的URL模式。Filter可以通过`chain.doFilter(request, response)`来将请求传递给下一个Filter或目标资源。 ### 应用场景 -...

    温故知新ASP.NET 2.0(C#)

    ASP.NET 2.0是微软开发的一个用于构建Web应用程序的框架,它基于.NET Framework,提供了丰富的功能和强大的性能。C#是一种面向对象的编程语言,是ASP.NET开发的主要语言之一,以其简洁、类型安全和高性能著称。在这...

    自己动手写Struts.pdf

    ### 自己动手写Struts:构建基于MVC的Web开发框架 #### 第一篇:Web框架入门 ##### 第1章 运筹帷幄:Web框架的核心思想 - **MVC模式** - **MVC模式概述**:MVC(Model-View-Controller)是一种常用的设计模式,...

    初中语文文学讨论现当代文学温故知新

    初中语文文学讨论现当代文学温故知新

    温故知新,通过学习尚学堂飞机游戏项目,理解Java语言基础知识.zip

    在本项目"温故知新,通过学习尚学堂飞机游戏项目,理解Java语言基础知识.zip"中,我们可以深入探讨Java编程语言的基础知识,并结合实际的游戏开发经验来加深理解。这是一个非常适合初学者或者想要巩固Java基础的...

    数学:吃透课本温故知新.docx

    考生应专注于理解和掌握每一个知识点,而不是一味追求学习的广度。要做到这一点,需要深入阅读课本,对每个概念都有精准的理解,不留下任何模糊不清的地方。同时,通过反复练习来熟悉和熟练掌握这些知识点,确保在...

    中信建设温故知新,从 4G 看 5G.rar

    《中信建设温故知新,从 4G 看 5G》这份资料主要探讨了移动通信技术从第四代(4G)到第五代(5G)的演进过程,以及这一演变带来的技术创新和产业影响。4G 和 5G 作为两个重要的通信时代,它们之间的差异和联系构成了...

    中信建设温故知新,从 4G 看 5G.pdf

    中信建设温故知新,从 4G 看 5G.pdf

Global site tag (gtag.js) - Google Analytics