`

模拟spring - 动手写一个spring IOC

 
阅读更多

一、前言

IOC (Inverse of control) - 控制反转,spring的IOC实现原理为利用Java的反射机制并充当工厂的角色完成对象的装配和注入。

二、实现细节

附上一张类的结构图,该例子需要导入jdom.jar和junit.jar



① 用户Bean

package com.zdp.model;

// 用户类
public class User {
	private String userName;
	private String password;

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}
② UserService

package com.zdp.service;

import com.zdp.dao.UserDao;
import com.zdp.model.User;

public class UserService {
	private UserDao userDao;

	public void add(User user) {
		userDao.save(user);
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
}
③ UserDao

package com.zdp.dao;

import com.zdp.model.User;

public class UserDao {
	
	public void save(User user) {
		System.out.println("user saved!");
	}
	
}
④ Bean工厂接口

package com.zdp.spring;

// Bean工厂接口
public interface BeanFactory {
	
	public Object getBean(String id);
	
}
⑤ Bean工厂实现

package com.zdp.spring;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

// Bean工厂实现类
public class ClassPathXmlApplicationContext implements BeanFactory {

	private Map<String, Object> beans = new HashMap<String, Object>();

	public ClassPathXmlApplicationContext() throws Exception {
		SAXBuilder sb = new SAXBuilder();
		Document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml")); // 构造文档对象
		Element root = doc.getRootElement(); // 获取根元素HD
		List list = root.getChildren("bean"); // 取名字为bean的所有元素
		for (int i = 0; i < list.size(); i++) {
			Element element = (Element) list.get(i);
			String id = element.getAttributeValue("id");
			String clazz = element.getAttributeValue("class");
			Object beanObj = Class.forName(clazz).newInstance(); // 反射获取对象
			beans.put(id, beanObj); // 将对象存入Bean工厂

			for (Element propertyElement : (List<Element>) element.getChildren("property")) { 
				String name = propertyElement.getAttributeValue("name"); // name="userDao"
				String bean = propertyElement.getAttributeValue("bean"); // bean="userDao"
				Object injectObject = beans.get(bean); // 从Bean工厂中获取UserDao
				String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); // setUserDao
				Method method = beanObj.getClass().getMethod(methodName, injectObject.getClass());
				method.invoke(beanObj, injectObject); // set注入UserDao对象
			}
		}
	}

	public Object getBean(String id) {
		return beans.get(id);
	}

}

这里为核心代码,当然在实际情况中,这一块要复杂的多, 例如:可以一个bean引用另一个bean,还可以有多个配置文件、通过多种方式载入配置文件等等,不过原理还是采用Java的反射机制。

⑥ 配置文件

<beans>
	<bean id="userDao" class="com.zdp.dao.UserDao" />
	<bean id="userService" class="com.zdp.service.UserService" >
		<property name="userDao" bean="userDao" />
	</bean>
</beans>
⑦ 单元测试

package com.zdp.service;

import org.junit.Test;

import com.zdp.model.User;
import com.zdp.spring.BeanFactory;
import com.zdp.spring.ClassPathXmlApplicationContext;

// 测试代码
public class UserServiceTest {

	@Test
	public void testAdd() throws Exception {
		BeanFactory applicationContext = new ClassPathXmlApplicationContext(); // 获取上下文
		UserService service = (UserService) applicationContext.getBean("userService"); // Spring装配Bean
		User user = new User();
		user.setUserName("zhangsan");
		user.setPassword("123456");
		service.add(user); // 将user保存入库
	}

}

三、小结

上文仅仅是简单地模拟了spring的IOC的实现,虽然只是完成了spring中依赖注入的一小部分,但还是很好地展现了Java反射机制在spring中的应用,对于初学者理解IOC应该会有一点帮助。

源码下载地址:http://download.csdn.net/detail/zdp072/7284983


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics