1.主要思想就是使用工廠設計模式,将service層和dao層進行解耦
控制反轉就是(inversion of control)将控制權交個自定的一個工廠來實作,我們要做的就是,通過自定義beanfactory 得到需要的serviceiml 和 daoiml對應的類
說白了,不用serviceiml依賴dao層
這裡使用ServletContextListener 監聽器來讓tomcat啟動時,加載配置檔案,
這裡就按照我自己的了解來說明,最近幾天研究的結果,當然有老師指導的結果-----------黑馬31期
1,進行監聽器的實作
目的:可以第一時間加載配置檔案
2. 配置檔案中注冊監聽器
<!-- 注冊Context監聽器 -->
<listener>
<listener-class>com.itheima.ebs.web.Listener.ApplicationContextListener</listener-class>
</listener>
3,當監聽器在tomcat啟動時加載配置檔案。配置檔案名:applicationContext.xml (預設)
public class ApplicationContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 0 獲得servletContext對象應用
ServletContext context = sce.getServletContext();
// 0.1加載配置
String config = context.getInitParameter("config");
if (config != null) {
// 1.1 處理路徑不同情況(我們都知道,配置檔案,
//可以放在src下面,可以放在web-inf下)
String[] arr = config.split(":");
//使用流的方式進行讀取
InputStream xmls = null;
try {
//如果放在classpath:applicationContext.xml
if (arr.length == 2) {
// 使用類加載器來加載配置檔案
xmls = ApplicationContextListener.class.getClassLoader()
.getResourceAsStream(arr[1]);
// 如果在WEB-INF下面
} else if (arr.length == 1) {
//使用servletContext的方法來加載
xmls = context.getResourceAsStream(config); // 放到WEB-INF下
}
} catch (Exception e) {
throw new RuntimeException("資源檔案加載不成功" + config);
}
// 如果不等于Null,加載到了配置檔案
if (xmls != null) {
// 2使用dom4j進行解析,為了友善查找,我們選在了map容器進行存儲
//定義了xmlUtil工具類,友善代碼的維護--傳回map集合
Map<String, Bean> data = XmlUtil.parserBeanXml(xmls);
//3 将解析結果放置到工廠中
BeanFactory.setBeanData(data);
}
}
}
4. 我們使用dom4j進行解析:
<beans>
<bean name="CategoryDao" class="com.itheima.ebs.dao.impl.CategoryDaoImpl">
</bean>
<bean name="UserDao" class="com.itheima.ebs.dao.impl.UserDaoiml">
</bean>
</beans>
public class XmlUtil {
public static Map<String, Bean> parserBeanXml(InputStream xml) {
try {
//定義一個容器
Map<String, Bean> data = new HashMap<String, Bean>();
// 1解析檔案,并獲得Document對象
SAXReader reader = new SAXReader();
// 2.擷取docuemnt
Document document = reader.read(xml);
// 3 得到 beans
Element root = document.getRootElement();
// 獲得bean 元素集合
List<Element> allBeanElements = root.elements();
// 周遊取值(name:value class:value)
for (Element elements : allBeanElements) {
String beanName = elements.attributeValue("name");
String beanClass = elements.attributeValue("class");
// 為了後期友善對xml、
檔案中配置擴充使用面向對象封裝的思想将bean對象封裝到特殊的 bean中
Bean bean = new Bean(beanName, beanClass);
data.put(beanName, bean);
}
//封裝好的bean進行傳回
return data;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
5 .bean對象的封裝
package com.itheima.ebs.Factory;
public class Bean {
private String beanName;
private String beanClass;
public Bean() { }
public Bean(String beanName, String beanClass) {
this.beanName = beanName;
this.beanClass = beanClass;
}
---《 setter/getter方法 》----
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++
BeanFactory:
beanfactory要提供一個自動生對應的bean對象,保證對象的唯一
這裡使用單例模式,加上反射思想,通過。class。fornam("類的全限定名").newInstance()
package com.itheima.ebs.Factory;
import java.util.Map;
/**
*
* 執行個體工廠-單例模式
*
* @return
*/
public class BeanFactory {
private static BeanFactory factory = new BeanFactory();
//存取bean的 key--value 的一個map對象
private static Map<String, Bean> beanData;
//bean 資料緩存集合
private BeanFactory() {}
public static BeanFactory getInstance() {
return factory;
}
//向外部提供一個getbean的方法
//因為是工廠類,是以不依賴任何外部類,使用object作為傳回類型
public Object getBean(String beanName) {
try {
//通過bean的名稱--value(map.get(key)-----value)
Bean bean=beanData.get(beanName);
String beanclass=bean.getBeanClass();
//初始化一個對象進行傳回
return Class.forName(beanclass).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void setBeanData(Map<String, Bean> beanData) {
//從配置檔案中讀取bean資訊傳入工廠,從工廠往外取
//使用提供一個set方法來共外界,将解析過的map容器,set到工廠中
BeanFactory.beanData=beanData;
}
}
這樣一個簡單的解耦,就可以實作了,我們就可以通過配置檔案,來指定sevice層--serviceimpl
serviceimpl層和dao層,--dao層和daoimpl的解耦。互相不進行依賴。