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

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

1. 前言

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

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

2.1 步驟介紹

思路分析:

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

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

開發(fā)準備

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

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

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

接口代碼如下

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

實現(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 用于存儲實例化的 bean 對象 ;
  2. 有參構(gòu)造方法邏輯暫時為空,下面會做實現(xiàn),加載文件實例化對象在方法內(nèi)部;
  3. getBean 的方法用于通過 key 獲取 map 中存儲的實例。

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

接口代碼如下

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

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

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

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

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

}

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

自定義一個 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 需要實例化 是因為 service 用到了它的引用,所以這里多個屬性 property。

編寫測試類加載文件測試

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());
	}

}

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

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

思路分析

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

2. 通過 SAXReader 解析 xml 文件的節(jié)點得到 beans 節(jié)點下對應多個 bean 節(jié)點集合;

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

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

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

完整代碼

public XmlSpringContext(String filename){
		
		// xml文件的解析器
		SAXReader  sr = new SAXReader();
		try {
			//構(gòu)建一個直接通向我們配置文件路徑 的輸入流
			InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filename);
			//文檔模型對象
			Document doc = sr.read(inputStream);
			//獲取根標簽
			Element root = doc.getRootElement();
			//獲取當前根標簽的子標簽
			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);
				//當前對象
				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ù)方法名稱獲取方法對象Method
						 Method method = myclass.getMethod(methodName,refobj.getClass().getInterfaces()[0]);					 
						 method.invoke(obj, refobj);
					}
				}
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}

測試結(jié)果:

圖片描述

3. 小結(jié)

本章節(jié)帶著大家模擬一下 Spirng 加載文件的過程和實例化對象的過程,當然這個過程只是模擬 Spring 的框架的思路,而并不是真正的 Spring 框架源碼,實際源碼遠比這個要復雜的多,

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

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

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