20140314 一起学Spring Framework 001 一个最简单的例子的实现

先来试一个最简单的例子

package gordon.study.spring.sample;

public class Employee {
	private String name;
	private String address;
	private Long badgeNumber;

	// getters and setters

	public void welcome() {
		System.out.printf("Welcome to our company, %s!", getName());
	}
}

package gordon.study.spring.sample;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Sample001 {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("sample1.xml");
		Employee gordon = (Employee) context.getBean("gordon");
		gordon.welcome();
	}
}

------------------------------sample1.xml--------------------------------

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
	<bean id="gordon" class="gordon.study.spring.sample.Employee">
		<property name="name" value="Gordon" />
	</bean>
</beans>

============================================================

例子太简单了以至于我不想对此写任何注释,让我来思考一下如何自己来实现它吧。


我们知道Spring Ioc的核心功能就是提供一个Ioc容器,该容器通过配置文件管理bean的生命周期,包括初始化一个bean和注入依赖关系。main函数无外乎就是通过读取一个xml文件获得bean的配置信息,生成一个容器(ApplicationContext),然后通过getBean方法让容器提供一个装配好的bean给自己使用。

毫无疑问,容器对Bean的创建和依赖的注入显然是通过反射实现的。而对于配置信息,我们将xml中的bean标签抽象成一个BeanDefinition类,BeanDefinition至少需要有id、clazz属性和一个property列表,property可以抽象为BeanProperty类。所有的BeanDefinition,可以通过一个map来管理。

读取xml文件选用dom4j 的 DOM 方式,这个最简单。

一个隐藏细节是:目前的scope是singleton的。也就是说无论我们调用多少次 getBean("gordon"),返回的都是同一个对象。Spring中默认就是 singleton


我们将代码移入一个新项目 mySpring,删除所有的对spring包的导入,然后开始自己实现。


============================================================

代码实现也非常简单,纯粹是用来热手的,就不复制过来了,可以去 https://github.com/klg0705/mySpring 获取,tag为 001-lw


唯一碰到的麻烦是如何读取classpath路径上的文件,暂时用以下方法获得文件路径:

		URL url = ClassLoader.getSystemResource(fileName);
		File f = new File(url.getFile());

另一件事情是如何匹配 setter 方法的参数类型

public class ClassPathXmlApplicationContext implements ApplicationContext {

	Map<String, BeanDefinition> beanDefinitions;

	Map<String, Object> beans;

	public ClassPathXmlApplicationContext(String fileName) throws Exception {
		beanDefinitions = XmlConfigReader.readXmlConfig(fileName);
		beans = new HashMap<String, Object>();
	}

	@Override
	public Object getBean(String beanName) throws Exception {
		if (beans.containsKey("beanName")) {
			return beans.get(beanName);
		}

		Object bean = createBean(beanName);

		beans.put(beanName, bean);

		return bean;
	}

	private Object createBean(String beanName) throws Exception {
		if (!beanDefinitions.containsKey(beanName)) {
			throw new Exception("Bean " + beanName + " cannot be found.");
		}

		BeanDefinition beanDef = beanDefinitions.get(beanName);
		Object obj = Class.forName(beanDef.getClazz()).newInstance();
		for (BeanProperty prop : beanDef.getProperties()) {
			getSetterMethod(obj, prop.getPropertyName()).invoke(obj, prop.getPropertyValue());
		}
		
		return obj;
	}

	private Method getSetterMethod(Object obj, String property) throws Exception {
		String setter = getSetterString(property);
		Method method = obj.getClass().getMethod(setter, String.class);
		return method;
	}

	private String getSetterString(String property) {
		StringBuilder sb = new StringBuilder("set");
		sb.append(Character.toUpperCase(property.charAt(0))).append(
				property.substring(1));
		return sb.toString();
	}
}

当前的实现中,只去找参数类型为 Stirng 的setter 方法(见getSetterMethod),显然,这只能保证目前的用例可以执行,其本身逻辑是错误的。这个问题将在下一篇解决。

<bug 14行代码无力吐槽了>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值