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

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

[quote]以下示例只为了解释原理而不是写一个成熟的IoC容器,因此尽可能的把与主题无关的代码给省略掉了,希望那些准备写自己的成熟容器的同学别学这个示例[/quote]


首先还是亲切的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的代码比较一下,是不是特别神似?[url]http://bolide74.iteye.com/blog/993248[/url]只不过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的源码哈,都是猜的,我想应该八九不离十,万一错了,千万别回头来找我算账,概不负责哦~ :D


下一篇:Spring温故知新(五)Spring的Bean和IoC 容器 [url]http://bolide74.iteye.com/blog/1004086[/url]
上一篇:Spring温故知新(三)singleton单例模式 [url]http://bolide74.iteye.com/blog/1001630[/url]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值