手写SpringIOC(读取bean的配置信息)

原创
2019/04/25 21:55
阅读数 520

先大致说一下思路:以流的形式读取一个配置文件,并将流中的信息解析并封装到一个map1<String,BeanDefinition>中,BeanDefinition包含了配置文件的属性信息,构建一个工厂,利用反射将构建的bean对象存入另一个map2<String,Object>中,方便从工厂直接获取对象. 其中map1作为工厂的原料(需要从配置文件中获取),map2作为工厂产品(有工厂为我们创建的bean对象).

先定义实体类 User.class

package com.spring;
/**
 * 实体类
 * @author wan_ys
 *
 */
public class User {
	private Integer id;
	private String name;
}

Order.class

package com.spring;
/**
 * 实体类
 * @author wan_ys
 *
 */
public class Order {
	private Integer id;
	private String item;
}

这里写一个简单的配置文件 spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="user" class="com.spring.User"></bean>
	<bean id="order" class="com.spring.Order"></bean>
</beans>

定义一个存放配置文件信息的类(属性与配置文件中的属性对应)

package com.spring;
/**
 * 包装配置文件中bean的配置信息
 * @author wan_ys
 *
 */
public class BeanDefinition {
	private String id;
	private String claString;//对应配置文件中的class属性
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getClaString() {
		return claString;
	}
	public void setClaString(String claString) {
		this.claString = claString;
	}
	@Override
	public String toString() {
		return "BeanDefinition [id=" + id + ", claString=" + claString + "]";
	}
}

模仿Spring写一个DefaultBeanFactory工厂

package com.spring;
/**
 * Bean工厂
 * @author wan_ys
 *
 */

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class DefaultBeanFactory {
	// 存储bean的信息(原料)
	Map<String, BeanDefinition> beanMap = new ConcurrentHashMap<String, BeanDefinition>();
	// 存储示例对象(产品)
	Map<String, Object> instanceMap = new ConcurrentHashMap<String, Object>();

	public DefaultBeanFactory(String configFilePath) {
		// 获取文件对应的流对象
		InputStream inputStream = ClassLoader.getSystemResourceAsStream(configFilePath);
		// 处理流对象
		handleStream(inputStream);
		// 处理Document对象
		// 处理Node对象,将数据封装到BeanDefinition对象中
	}

	/*
	 * 处理读取的配置文件流
	 */
	private void handleStream(InputStream inputStream) {
		try {
			//构建解析器对象
			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			//将流解析为Document对象
			Document document = builder.parse(inputStream);
			//处理Document对象
			handleDocument(document);
				
			
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/*
	 * 处理Document对象
	 */
	private void handleDocument(Document document) {
		// 获取所有bean元素
		NodeList nodeList = document.getElementsByTagName("bean");
		// 迭代所有的bean元素,先获取一个Node节点,将节点转成BeanDefinition对象之后存入beanMap(原料)
		for (int i = 0; i < nodeList.getLength(); i++) {
			// 获取第i个元素
			Node node = nodeList.item(i);
			// 处理Node对象,并将返回的BeanDefinition对象存入beanMap
			BeanDefinition beanDefinition = handleNode(node);
			beanMap.put(beanDefinition.getId(), beanDefinition);
		}

	}

	/*
	 * 处理Node,转成BeanDefinition
	 */
	private BeanDefinition handleNode(Node node) {
		//构建BeanDefinition对象,存储Node信息
		BeanDefinition beanDefinition=new BeanDefinition();
		//获取节点相关属性值
		NamedNodeMap nodeMap = node.getAttributes();
		String id = nodeMap.getNamedItem("id").getNodeValue();
		String claString = nodeMap.getNamedItem("class").getNodeValue();
		//将节点值存入BeanDefinition对象
		beanDefinition.setId(id);
		beanDefinition.setClaString(claString);
		return beanDefinition;
	}
	/*
	 * 创建对象
	 */
	private Object createInstance(Class<?> class1) {
		try {
			Constructor<?> constructor = class1.getDeclaredConstructor();
			return constructor.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	public <T>T getBean(String id,Class<T> class1){
		//对传入的id和class1进行校验
		if (!beanMap.containsKey(id)) {
			throw new RuntimeException("没有该id的bean对象");
			
		}
		BeanDefinition definition = beanMap.get(id);
		if (!class1.getName().equals(definition.getClaString())) {//User.class的getName与definition对象中获取的class属性是否相同
			throw new RuntimeException("没有对应类的bean对象");
		}
		//从instanceMap中获取对象
		Object object = instanceMap.get(id);
		if (object==null) {
			object=createInstance(class1);
			instanceMap.put(id, object);
		}
		return (T) object;
	}

}

下面做一个测试

package com.spring;

public class Test {
	public static void main(String[] args) {
		DefaultBeanFactory defaultBeanFactory=new DefaultBeanFactory("spring-config.xml");
		User bean = defaultBeanFactory.getBean("user", User.class);
		User bean2 = defaultBeanFactory.getBean("user", User.class);
		System.out.println(bean); //com.spring.User@4e25154f
		System.out.println(bean==bean2); //true

	}

}

展开阅读全文
0
3 收藏
分享
加载中
更多评论
打赏
0 评论
3 收藏
0
分享
返回顶部
顶部