自定義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;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章