spring的简单模拟

这篇博文主要模拟spring的ClassPathXmlApplicationContext的getBean(id)方法,以及实体类值得注入。

思路大概是解析 bean.xml文件,获取 bean的ID及class。通过解析到的类名就可以反射获取到该类的方法及实例 对象,最后注值。

1.先看下项目整体结构

2.准备好两个实体类。StuManager里面有一个Student的引用,这是为了模拟后面的ref注值。

 

3.创建ApplicationContext接口

package org.springframework.context;

public interface ApplicationContext {
  public Object getBean(String beanId);
}

4.创建ClassPathXmlApplicationContext类

package org.springframework.context;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


public class ClassPathXmlApplicationContext implements ApplicationContext{

	//这个map集合用来代表IOC容器
	Map<String , Object> map = new HashMap<String, Object>();

	public  ClassPathXmlApplicationContext(String xmlFile) throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

		//解析beans文件
		InputStream is = this.getClass().getClassLoader().getResourceAsStream(xmlFile);
		SAXReader reader = new SAXReader();
		Document doc = reader.read(is);
		Element root = doc.getRootElement();
		//获取所有bean信息
		List<Element> beans = root.elements();
		//遍历
		for (Element bean : beans) {
			String id=bean.attributeValue("id");
			String className = bean.attributeValue("class");
			//根据读取的类名创建字节码对象
			//反射创建对象的三种方式:1.通过类名创建.。2.通过类对象创建  3.通过Class.forName(全类名)
			Class cls=Class.forName(className);
			//通过字节码对象去创建实例
			Object obj = cls.newInstance();
			//把创建好的对象放进容器里
			map.put(id, obj);

			//获取所有方法
			Method[] methods = cls.getMethods();
			//获取要注入的属性值
			List<Element> pros = bean.elements();
			//遍历方法
			for (Method method : methods) {
				//获取set方法
				String methodName = method.getName();
				if (methodName.startsWith("set")) { //如果是set开头的方法名,说明此方法是set方法
					//遍历属性值
					for (Element pro:pros) {
						//获取属性名
						String proName = pro.attributeValue("name");
						//判断方法和属性是否匹配
						if (methodName.substring(3).equalsIgnoreCase(proName)) {
							//获取属性值
							String proValue = pro.attributeValue("value");
							//传入参数到方法后执行
							if (proValue!=null) {
								method.invoke(obj, proValue);
							}else { //说明它是一个ref属性
								method.invoke(obj, map.get(pro.attributeValue("ref")));
							}
						}
					}

				}
			}
		}
	}

	@Override
	public Object getBean(String beanId) {
		return map.get(beanId);
	}

}

5.写一个bean.xml。放在src目录下。

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="stu" class="bean.Student">
		<property name="id" value="1001"></property>
		<property name="name" value="张三"></property>
	</bean>
	<bean id="stum" class="bean.StuManager">
		<property name="student" ref="stu"></property>
	</bean>
</beans>

6.测试运行

public class _main {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, DocumentException, IllegalArgumentException, InvocationTargetException {
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		Student stu = (Student)ac.getBean("stu");
		StuManager stm = (StuManager) ac.getBean("stum");
		System.out.println(stu);
		System.out.println(stm);
	}
}

 

猜你喜欢

转载自blog.csdn.net/LiangCJP/article/details/82807471