自定义spring-ioc

本次代码实现了spring中ioc模块的基本功能

前提:有JavaWeb基础,xml基础

先演示效果,再深入分析源码,后面有源码和说明

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="stu1" className="home.sise.cn.Student">
		<property name="number" value="110"/>
		<property name="name" value="zhangSan"/>
		<property name="age" value="29"/>
		<property name="sex" value="male"/>
		<property name="teacher" ref="t1"/><!-- ref的值必须是另一个been的id -->
	</bean>
	<bean id="t1" className="home.sise.cn.Teacher">
		<property name="tid" value="120" />
		<property name="name" value="liSi" />
		<property name="salary" value="123.456" />
	</bean>
</beans>

主类

public class Demo {
	@Test
	public void fun() {
		/*
		 * 1. 创建Bean工厂,创建时需要给工厂指定配置文件
		 * 2. 从工厂中获取bean对象
		 */
		BeanFactory bf = new BeanFactory("beans.xml");
		Student s1 = (Student)bf.getBean("stu1");
		Student s2 = (Student)bf.getBean("stu1");
		System.out.println(s1 == s2);
		System.out.println(s1.toString());
		System.out.println(s1.getTeacher().toString());
	}
	}

student实体类

public class Student {
	private String number;
	private String name;
	private int age;
	private String sex;
	private Teacher teacher;
	
	public Teacher getTeacher() {
		return teacher;
	}
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}

	public String toString() {
		return "Student [number=" + number + ", name=" + name + ", age=" + age
				+ ", sex=" + sex + "]";
	}
	public Student() {
		super();
	}
	public Student(String number, String name, int age, String sex) {
		super();
		this.number = number;
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
}

Teacher实体类

public class Teacher {
	private String tid;
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	private double salary;
	public String getTid() {
		return tid;
	}
	public void setTid(String tid) {
		this.tid = tid;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	@Override
	public String toString() {
		return "Teacher [tid=" + tid + ", salary=" + salary + "]";
	}
	public Teacher() {
		super();
	}
	public Teacher(String tid, double salary) {
		super();
		this.tid = tid;
		this.salary = salary;
	}
}

运行结果
在这里插入图片描述

开始分析(源码后面都会给出,重点都有注释)

代码逻辑
BeanFactory bf = new BeanFactory(“beans.xml”);
在BeanFactory加载时,加载名为bean.xml的配置文件,然后把它里面的所有节点元素通过遍历解析成对象。加载后,整个bean.xml中所有节点对应产生的对象都封装到了BeanFactory中。

这里是把<bean>节点解析成BeanConfig对象
<property>节点解析成PropertyConfig对象
然后把PropertyConfig对象放入BeanConfig对象中

Student s1 = (Student)bf.getBean(“stu1”);
调用BeanFactory的getBean方法,把BeanFactory中名为stu1的BeanConfig对象找到,然后通过判断它是否为单例模式,如果是,从缓存中拿出来,没有则创建对象后放入缓存
如果值是prototype(即多例)则创建一个新的对象。然后返回student对象

在创建student对象时,先用通过传入的(”stu1“),在BeanFactory中找到对应的BeanConfig,然后通过解析BeanConfig中的属性className中的值,利用反射技术,得到student对象实例。并且把BeanConfig中的值封装给stuent对象。
封装时需要还要判断它的ref是否有值,即在beans.xml中的bean节点property下是否有ref属性,如果有,则封装
sutdent的属性时,把beans.xml中名为name的,值为ref的封装给student
如果没有ref属性,则把beans.xml中名为name的,值为value的封装给student

具体源码如下

BeanFactory源码

public class BeanFactory {
	// 配置文件的对应体
	private Map<String, BeanConfig> bcs = new HashMap<String, BeanConfig>();
	// Bean缓存,id是键, Bean是值
	private Map<String, Object> beanCache = new HashMap<String, Object>();
	
	public BeanFactory(String xmlName) {
		BeanFactoryUtils.load(this, xmlName);
	}
	
	// 如果缓存中存在,直接返回
	// 如果不存在,创建Bean,放入缓存中,再返回
	public Object getBean(String id) {
		BeanConfig bc = bcs.get(id);
		if(bc == null) {
			throw new RuntimeException(id + "不存在!");
		}
		if(bc.getScope() == null || bc.getScope().equals("singleton")) {
			// 如果是单例bean,查看缓存中是否存在,如果存在直接返回
			if(beanCache.containsKey(id)) {
				return beanCache.get(id);
			}
			// 如果缓存中不存在,那么创建之,然后放入缓存中,再返回
			Object bean = createBean(id);
			beanCache.put(id, bean);
			return bean;
		} else if(bc.getScope().equals("prototype")) {
			// 如果是原型bean,那么直接创建,然后返回,不用向入缓存
			Object bean = createBean(id);
			return bean;	
		}
		throw new RuntimeException("scope只能是singleton或prototype");
	}
	
	//创建对象
	private Object createBean(String id) {
		try {
			BeanConfig bc = bcs.get(id);//获取Bean配置对象
			Class c = Class.forName(bc.getClassName());
			Object bean = c.newInstance();
			Map<String, PropertyConfig> pcs = bc.getPropertyConfigMap();
			// 遍历所有的PropertyConfig
			for(String propName : pcs.keySet()) {
				PropertyConfig pc = pcs.get(propName);
				if(pc.getRef() != null) {
					String ref = pc.getRef();//是不是另一个bean的id
					Object refBean = getBean(ref);
					BeanUtils.setProperty(bean, pc.getName(), refBean);
				} else {
					BeanUtils.setProperty(bean, pc.getName(), pc.getValue());
				}
			}
			return bean;
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}

	public void addBeanConfig(BeanConfig bc) {
		bcs.put(bc.getId(), bc);
	}
	
	public BeanConfig getBeanConfig(String id) {
		return bcs.get(id);
	}

	public Map<String, BeanConfig> getBcs() {
		return bcs;
	}

	public void setBcs(Map<String, BeanConfig> bcs) {
		this.bcs = bcs;
	}
	
	
}

BeanFactoryUtils源码

public class BeanFactoryUtils {
	public static void load(BeanFactory factory, String xmlName) {
		Document doc = new SAXReader().read(Thread.currentThread().getContextClassLoader()
					.getResource(xmlName).getPath();//通过xmlName文件的位置,获取Document节点
		List<Element> beanEleList = doc.selectNodes("//bean");//通过xpath表达式获取Document中所有<bean>元素集合
		for(Element beanEle : beanEleList) {//遍历<bean>元素
			BeanConfig bc = XmlUtils.toBean(beanEle, BeanConfig.class);//把每个<bean>元素解析成一个BeanConfig对象
			List<Element> propEleList = beanEle.elements();
			// 把所有的PropertyConfig添加到BeanConfig中
			for(Element propEle : propEleList) {// 遍历<bean>中每个<property>元素
				PropertyConfig pc = XmlUtils.toBean(propEle, PropertyConfig.class);//把每个<property>元素解析成一个PropertyConfig对象
				
				bc.addPropertyConfig(pc);
			}
			factory.addBeanConfig(bc);
		}
	}
}

XmlUtils源码

public class XmlUtils {
	public static <T> T toBean(Element e, Class<T> clazz) {
		try {
			Map map = toMap(e);//把传入的Element封装成一个map集合
			T bean = clazz.newInstance();
			BeanUtils.populate(bean, map);//通过BeanUtils把map中的值映射到bean中
			return bean;
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}
		public static Map<String, String> toMap(Element e) {
		Map<String, String> map = new LinkedHashMap<String, String>();
		/*
		 * 循环遍历e的所有属性 循环遍历e的所有子元素(条件:只是纯文本内容的子元素)
		 */
		/*
		 * 把e的所有属性添加到map中
		 */
		List<Attribute> attrs = e.attributes();
		for (Attribute a : attrs) {
			map.put(a.getName(), a.getValue());
		}
		/*
		 * 把e的所有子元素(纯属文本内容的子元素)添加到map中
		 */
		List<Element> eles = e.elements();
		for (Element ele : eles) {
			if (ele.isTextOnly()) {
				map.put(ele.getName(), ele.getText());
			}
		}
		return map;
	}
	}

BeanConfig源码

public class BeanConfig {
	private String id;
	private String className;
	private String scope;
	
	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		if(!scope.equals("singleton") && !scope.equals("prototype")) {
			throw new RuntimeException("scope只能是singleton或prototype");
		}
		this.scope = scope;
	}

	private Map<String, PropertyConfig> propertyConfigMap = 
				new LinkedHashMap<String, PropertyConfig>();
	
	// 添加proertyConfig
	// propertyConfig.getName()为键, propertyConfig本身是值
	public void addPropertyConfig(PropertyConfig propertyConfig) {
		propertyConfigMap.put(propertyConfig.getName(), propertyConfig);
	}
	
	public PropertyConfig getPropertyConfig(String name) {
		return propertyConfigMap.get(name);
	}

	public Map<String, PropertyConfig> getPropertyConfigMap() {
		return propertyConfigMap;
	}

	public void setPropertyConfigMap(Map<String, PropertyConfig> propertyConfigMap) {
		this.propertyConfigMap = propertyConfigMap;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public BeanConfig() {
		super();
		// TODO Auto-generated constructor stub
	}

	public BeanConfig(String id, String className) {
		super();
		this.id = id;
		this.className = className;
	}

	@Override
	public String toString() {
		return "BeanConfig [id=" + id + ", className=" + className
				+ ", propertyConfigMap=" + propertyConfigMap + "]";
	}
}

PropertyConfig源码

public class PropertyConfig {
	private String name;
	private String value;
	private String ref;
	@Override
	public String toString() {
		return "PropertyConfig [name=" + name + ", value=" + value + ", ref="
				+ ref + "]";
	}
	public PropertyConfig(String name, String value, String ref) {
		super();
		this.name = name;
		this.value = value;
		this.ref = ref;
	}
	public PropertyConfig() {
		super();
		// TODO Auto-generated constructor stub
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public String getRef() {
		return ref;
	}
	public void setRef(String ref) {
		this.ref = ref;
	}
}
发布了24 篇原创文章 · 获赞 14 · 访问量 659

猜你喜欢

转载自blog.csdn.net/weixin_44860598/article/details/104543777