簡單實現Spring中BeanFactory原理


上一篇文章介紹了Java反射機制在Spring IOC中的應用,知道了BeanFactory底層的實現原理。

原理搞懂了,對Spring IOC理解起來也很容易。

先來看看Java代碼獲取Spring中Bean的代碼(一共有五種方式,這里只展示其中一種方法):

有沒有發現上面的代碼與利用反射實現工廠模式的代碼很相似。對,你沒有看錯,Spring中的BeanFactory用到的就是簡單工廠模式。

現在的思路就更加清晰了,要想實現Spring中的BeanFactory,無非就用到了以下幾個技術:

        1.使用簡單工廠模式來處理bean容器。

        2.解析xml文件,獲取配置中的元素信息。

        3.利用反射獲實例化配置信息中的對象。

        4.如果有對象注入,使用invoke()方法。

        5.實例化的對象放入bean容器中,並提供getBean方法。

通過以上步驟就實現了spring的BeanFactory功能,只要在配置文件中配置好,實例化對象的事情交給BeanFactory來實現,用戶不需要通過new對象的方式實例化對象,直接調用getBean方法即獲取對象實例。

具體實現代碼:

新建一個xml文件,內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    
    <bean id="courseDao" class="com.qcjy.learning.Dao.impl.CourseDaoImpl">


    <bean id="courseService" class="com.qcjy.learning.service.impl.CourseServiceImpl">
	     <!-- 控制調用setCourseDao()方法,將容器中的courseDao bean作為傳入參數 -->
	     <property name="courseDao" ref="courseDao"></property>
	</bean>
	
</beans>

 接下來實現BeanFactory工廠,提供init方法,和getBean方法,在init方法中解析xml,利用反射實例話對象,存入bean容器中,代碼如下:

import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

 

public class BeanFactory {
	
      //bean容器
	private Map<String, Object> contianer = new HashMap<String, Object>();
	
	/**
	 * <p>Discription:bean工廠的初始化</p>
	 * @param xml xml配置文件路徑
	 * @author       : lcma
	 * @update       : 2016年9月20日上午9:04:41
	 */
	public void init(String xml) {
		try {
			// 讀取指定的配置文件
			SAXReader reader = new SAXReader();
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			// 從class目錄下獲取指定的xml文件
			InputStream ins = classLoader.getResourceAsStream(xml);
			Document doc = reader.read(ins);
			Element root = doc.getRootElement();
			Element foo;
			// 遍歷bean
			for (Iterator i = root.elementIterator("bean"); i.hasNext();) {
				foo = (Element) i.next();
				// 獲取bean的屬性id和class
				Attribute id = foo.attribute("id");
				Attribute cls = foo.attribute("class");
				// 利用Java反射機制,通過class的名稱獲取Class對象
				Class<?> bean = Class.forName(cls.getText());
				// 獲取對應class的信息
				java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);
				// 獲取其屬性描述
				java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
				// 設置值的方法
				Method mSet = null;
				// 創建一個對象
				Object obj = bean.newInstance();
				// 遍歷該bean的property屬性
				for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {
					Element foo2 = (Element) ite.next();
					// 獲取該property的name屬性
					Attribute name = foo2.attribute("name");
					String value = null;
					// 獲取該property的子元素value的值
					for (Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {
						Element node = (Element) ite1.next();
						value = node.getText();
						break;
					}
					for (int k = 0; k < pd.length; k++) {
						if (pd[k].getName().equalsIgnoreCase(name.getText())) {
							mSet = pd[k].getWriteMethod();
							// 利用Java的反射機制調用對象的某個set方法,並將值設進去
							mSet.invoke(obj, value);
						}
					}
				}
				// 將對象放入beanMap中,其中key為id值,value為對象
				contianer.put(id.getText(), obj);
			}
		} catch (Exception e) {
			System.out.println(e.toString());
		}
	}
	
	/**
	 * <p>Discription:通過bean的id在容器中獲取bean對象</p>
	 * @param beanName bean的唯一標識id
	 * @return
	 * @author       : lcma
	 * @update       : 2016年9月20日上午9:05:00
	 */
	public Object getBean(String beanName) {
		Object obj = contianer.get(beanName);
		return obj;
	}

}

 測試方法:

	/**
	 * <p>Discription:測試方法</p>
	 * @param args
	 * @author       : lcma
	 * @update       : 2016年9月20日上午9:06:06
	 */
	public static void main(String[] args) {
        //實例化BeanFactory
		BeanFactory factory = new BeanFactory();
		//調用初始化方法,傳入xml路徑
		factory.init("spring.xml");
		//通過bean id 獲取對象
		CourseService courseService = (CourseService) factory.getBean("courseService");
		//調用對象方法
		courseService.findAll();
	}

 還要提供CourseService和CourseDao兩個接口及實現類,這里就不提供了。

上面的代碼已經簡單的模擬實現了BeanFactory的功能啦,Spring框架里面的代碼要比我們這個復雜的多,因為要考慮到安全性、穩定性、異常等等因素,但是原理都一樣。

https://blog.csdn.net/mlc1218559742/article/details/52776160


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM