第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁 慕課教程 Spring 入門教程 Spring 入門教程 Spring 框架模擬實(shí)現(xiàn)

Spring 框架模擬實(shí)現(xiàn)

1. 前言

通過幾個(gè)章節(jié)的學(xué)習(xí),大家對(duì)于 Spring 已經(jīng)有了初步的認(rèn)知,我們通過案例練習(xí),或者源碼追蹤,可以粗略的看到 Spring 框架初始化 bean 對(duì)象的過程,那么這個(gè)章節(jié),我們模擬 Spring 框架的思路,來寫一個(gè)類似 Spring 加載對(duì)象的案例,加深大家的印象。

2. 案例實(shí)現(xiàn)思路

2.1 步驟介紹

思路分析:

我們通過寫過的案例可以知道:

  1. Spring 框架的容器 是一個(gè)接口 ApplicationContext 和接口的實(shí)現(xiàn)類 ClassPathXmlApplicationContext 來初始化的;
  2. 在初始化容器對(duì)象的時(shí)候需要傳遞 xml 配置文件的位置;
  3. xml 的配置文件中主要是通過 bean 標(biāo)簽可以對(duì) Java 的類進(jìn)行描述:類的路徑 類的標(biāo)識(shí) 類的構(gòu)造參數(shù)等等;
  4. 容器初始化以后需要解析 xml 配置文件的各個(gè) bean 標(biāo)簽;
  5. 實(shí)例化的對(duì)象如果有參數(shù)或者構(gòu)造方法,那么也需要給參數(shù)賦值;

開發(fā)準(zhǔn)備

為了方便理解測(cè)試 ,我們來自定義容器的接口和實(shí)現(xiàn)類。

名稱改為 SpringContextXmlSpringContext 區(qū)別于框架的接口和實(shí)現(xiàn)類。

接口定義方法 getBean 用于獲取容器內(nèi)的示例,實(shí)現(xiàn)類定義有參構(gòu)造用于接受初始化時(shí)候的配置文件路徑。

接口代碼如下

public interface SpringContext {
    public Object getBean(String beanName);
}

實(shí)現(xiàn)類代碼如下:

public class XmlSpringContext  implements SpringContext  {

    Map<String,Object> map = new HashMap<String,Object>();
    
    public XmlSpringContext (String filename){	

    }
    
    public Object getBean(String beanName){		
    	return map.get(beanName);
    }

}

代碼解釋

  1. map 用于存儲(chǔ)實(shí)例化的 bean 對(duì)象 ;
  2. 有參構(gòu)造方法邏輯暫時(shí)為空,下面會(huì)做實(shí)現(xiàn),加載文件實(shí)例化對(duì)象在方法內(nèi)部;
  3. getBean 的方法用于通過 key 獲取 map 中存儲(chǔ)的實(shí)例。

為了測(cè)試對(duì)象的實(shí)例化,我們自定義 UserServiceUserServiceImpl 作為測(cè)試的接口對(duì)象和實(shí)現(xiàn)類。

接口代碼如下

public interface UserService {
	
	public void deleteById(Integer id);
	
}

接口的實(shí)現(xiàn)類代碼如下

public class UserServiceImpl implements UserService {
	//持久層的dao屬性
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }
	
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
	//實(shí)現(xiàn)接口的方法
    public void deleteById(Integer id) {

        System.out.println("刪除的方法執(zhí)行");
    }

}

代碼解釋:dao 的屬性其實(shí)是為了模擬屬性賦值,后面依賴注入章節(jié)會(huì)詳細(xì)講解。

自定義一個(gè) xml 文件 作為模擬框架的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans>
     <bean name="userDao" class="com.wyan.dao.UserDaoImpl"></bean>
     <bean name="userService" class="com.wyan.service.UserServiceImpl">
         <property name="userDao" ref="userDao"></property>
     </bean>     				
</beans>

代碼解釋:userDao 的 bean 需要實(shí)例化 是因?yàn)?service 用到了它的引用,所以這里多個(gè)屬性 property。

編寫測(cè)試類加載文件測(cè)試

public class TestSpring {

	@Test
	public void test() {
		//初始化容器(讀取配置文件 構(gòu)建工廠)
		SpringContext context =
                new XmlSpringContext("applicationContext.xml");
        UserServiceImpl userService = (UserServiceImpl) context.getBean("userService");
        userService.deleteById(1);
        System.out.println(userService.getUserDao());
	}

}

代碼解釋:這里的目的只是測(cè)試能否獲取對(duì)象調(diào)用方法,如果控制臺(tái)打印證明案例成功

2.2 容器對(duì)象的實(shí)現(xiàn)類構(gòu)造函數(shù)具體代碼

思路分析

1. 讀取初始化時(shí)候傳遞的文件路徑;

2. 通過 SAXReader 解析 xml 文件的節(jié)點(diǎn)得到 beans 節(jié)點(diǎn)下對(duì)應(yīng)多個(gè) bean 節(jié)點(diǎn)集合;

3. 每一個(gè) bean 表示一個(gè)對(duì)象,都需要被初始化,所以需要循環(huán)遍歷集合;

4. 在循環(huán)遍歷的過程中獲取 id 屬性和 class 屬性,id 屬性作為存入 map 的 key,class 屬性用于反射實(shí)例化對(duì)象,并存儲(chǔ) map 的 value;

5. 繼續(xù)解析子節(jié)點(diǎn),如果有參數(shù),反射獲取 method 執(zhí)行參數(shù)賦值。

完整代碼

public XmlSpringContext(String filename){
		
		// xml文件的解析器
		SAXReader  sr = new SAXReader();
		try {
			//構(gòu)建一個(gè)直接通向我們配置文件路徑 的輸入流
			InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filename);
			//文檔模型對(duì)象
			Document doc = sr.read(inputStream);
			//獲取根標(biāo)簽
			Element root = doc.getRootElement();
			//獲取當(dāng)前根標(biāo)簽的子標(biāo)簽
			List<Element>  beans = root.elements("bean");
			for(Element bean:beans){			
				String key = bean.attributeValue("name");
				String value = bean.attributeValue("class");
				Class<?> myclass = Class.forName(value);
				//當(dāng)前對(duì)象
				Object obj = myclass.newInstance();
				map.put(key, obj);				
				List<Element> elements = bean.elements("property");
				if(elements.size()>0){
					for(Element pro: elements){
						 String av = pro.attributeValue("name");//dao--->setDao
						 //方法名
						 String methodName="set"+(av.charAt(0)+"").toUpperCase()+av.substring(1,av.length());						 
						 //方法參數(shù)
						 String refvalue = pro.attributeValue("ref");
						 Object refobj = map.get(refvalue);						 
						 //根據(jù)方法名稱獲取方法對(duì)象Method
						 Method method = myclass.getMethod(methodName,refobj.getClass().getInterfaces()[0]);					 
						 method.invoke(obj, refobj);
					}
				}
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}

測(cè)試結(jié)果:

圖片描述

3. 小結(jié)

本章節(jié)帶著大家模擬一下 Spirng 加載文件的過程和實(shí)例化對(duì)象的過程,當(dāng)然這個(gè)過程只是模擬 Spring 的框架的思路,而并不是真正的 Spring 框架源碼,實(shí)際源碼遠(yuǎn)比這個(gè)要復(fù)雜的多,

那么通過本章節(jié)我們收獲哪些知識(shí)呢?

  1. Spring 容器類的使用
  2. xml 配置文件的作用
  3. 反射技術(shù)的應(yīng)用

我不相信不勞而獲,如果有誰告訴你,他可以做到 XX 速成,請(qǐng)遠(yuǎn)離他,他連基本的誠信都沒有…