一:IOC容器的概述java
1.1 IOC容器和依賴反轉模式編程
依賴反轉:依賴的對象得到了反轉,還有叫依賴注入的,咱們都知道不少應用都是由多個類經過彼此的合做來實現業務邏輯的,這使每一個對象都須要與其合做對象的引用,若是獲取過程靠自身實現,會致使代碼高度耦合而且難以測試設計模式
首先我簡單說一下java對象是怎麼樣的一個實例化過程:架構
(1)檢查類是否加載,若是沒有加載就加載這個類,而且加載全部父類,簡單說就是建立完類會生成.java文件,而後經過IDEA或者其餘編譯器javac命令生成.class文件app
(2)虛擬機會經過main方法入口,尋找到new關鍵字在內存堆中分配對象空間,遞歸分配全部父類和子類屬性空間,先父類在子類,屬性默認自動初始化,自動初始化爲「0」值框架
(3)進行屬性的賦值,遞歸調用父類構造器(默認調用父類無參構造器)在調用本類構造器測試
舉個例子:this
下面有一個描述帳戶的類spa
public class Account { private Integer id; private String name;//用戶名稱 private Double money;//帳戶金額 //getter setter toString }
建立AccountDao接口及其實現類,模擬新增帳戶方法設計
public interface AccountDao { /** * 保存帳戶信息 */ void save(Account account); }
public class AccountDaoImpl implements AccountDao { public void save(Account account) { System.out.println("模擬保存帳戶:保存成功啦!!!"); } }
建立AccountService接口及其實現類,模擬新增帳戶方法
public interface AccountService { /** * 保存帳戶信息 */ void save(Account account); }
public class AccountServiceImpl implements AccountService { private AccountDao accountDao = new AccountDaoImpl();//此處有耦合 public void save(Account account) { accountDao.save(account); } }
咱們使用面向對象的系統能夠對某一類的事物進行增刪改查,可是會有一個問題,若是合做的對象的引用或依賴關係的管理由具體的對象來完成,會致使代碼的高度耦合和可測試性下降,要是把這種對於對象的封裝和數據的處理,對象的依賴關係交給框架或IOC容器來完成,便可以解耦也可提升代碼的可測試性
那是Spring容器的是怎麼解耦的呢?
咱們就以XML方式爲例
首先建立beans.xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!-- 配置須要注入自定義IOC容器的對象 id 惟一標識 class 類全限定名 --> <beans> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"/> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/> </beans>
建立Bean工廠類:初始化Bean工廠時建立全部的對象,裝載到工廠
public class BeanFactory { //IOC容器的本質其實就是一個Map集合;key-value,key是惟一標識,value是建立好的對象 private static Map<String,Object> map = new HashMap<String, Object>(); /** * 目標:自定義IOC容器,實現三層架構解耦。 * 解耦三層架構:將對象的建立,交給Bean工廠, * 須要對象的時候直接從工廠中取,而不是本身new。 * 1.建立Beans.xml配置文件 * 2.類加載器讀取Beans.xml配置文件輸入流 * 3.建立xml文件解析器SAXReader,解析XML文件 * 4.用XPath取出配置文件中的全部bean標籤,返回元素的集合對象 * 5.循環遍歷標籤list集合,取出bean標籤的id和class * 6.射建立對象,裝進自定義ioc容器 * 7.Bean工廠對外提供方法,獲取自定義IOC容器中的對象 */ static { //2.類加載器讀取Beans.xml配置文件輸入流 InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml"); try { //3.建立xml文件解析器SAXReader,解析XML文件 SAXReader saxReader = new SAXReader(); Document document = saxReader.read(inputStream); //4.用XPath取出配置文件中的全部bean標籤,返回元素的集合對象 List<Element> elementNodes = document.selectNodes("//bean"); //5.循環遍歷標籤list集合,取出bean標籤的id和class for (Element element : elementNodes) { //6.射建立對象,裝進自定義ioc容器 //<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"/> String idValue = element.attributeValue("id"); String classValue = element.attributeValue("class"); Class<?> clazz = Class.forName(classValue); Object obj = clazz.newInstance(); //裝進自定義ioc容器 map.put(idValue,obj); } } catch (DocumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 7.Bean工廠對外提供方法,獲取自定義IOC容器中的對象 * 根據bean對象惟一標識獲取工廠中建立好對象 */ public static Object getBean(String id){ return map.get(id); } }
在AccountService實現類中,經過工廠獲取對象
public class AccountServiceImpl implements AccountService { //耦合 //private AccountDao accountDao = new AccountDaoImpl(); private AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao"); public void save(Account account) { accountDao.save(account); } }
編寫測試類
public class TestCustomIoc { @Test public void test(){ //AccountService accountService = new AccountServiceImpl(); AccountService accountService = (AccountService) BeanFactory.getBean("accountService"); accountService.save(new Account()); } }
二.IoC中兩個主要的容器系列
1.實現了BeanFactory接口的簡單容器系統,實現了容器的最基本功能
2.ApplicationContext應用上下文,做爲容器的高級形態存在.
從上面接口設計圖中能夠看到兩條主要的設計主線:
第一條從BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,是主要的BeanFactory設計路徑.經過這些接口設計的疊加,定義了BeanFactory就是簡單IoC容器的基本功能.
第二條是以ApplicationContext應用上下文接口爲核心的接口設計.對於AppilcationContext除了細化了許多BeanFactory的接口能外以外,還經過繼承MessageSource、ResourceLoader、ApplicationEventPublisher接口,添加了許多對高級容器的特性的支持.
- 容器中起做用的主要數據類型是BeanDefinition,它是對依賴反轉模式中管理的對象依賴關係的數據抽象,依賴反轉功能都是圍繞着對這個BeanDefinition的處理完成的.
三:BeanFactory的應用場景
1.BeanFactory提供的是最基本的IoC容器的功能,關於這些功能定義,咱們能夠在接口BeanFatory中看到。
2.BeanFactory接口定義了IoC容器最基本的容器的形式,而且提供了IoC容器所應該遵照的最基本的服務契約,同時,這也是咱們使用IoC容器所應遵照的最底層和最基本的編程規範,這些接口定義勾畫出了IoC的基本輪廓。
3.很顯然,在Spring的代碼實現中,BeanFactory只是一個接口類,並無給出容器的具體實現,而咱們在圖中看到的各類具體類,好比DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等均可以當作是容器附加了某種功能的具體實現,也就是容器體系中的具體容器產品
1.用戶使用容器時,可使用轉義符"&"來獲得FactoryBean自己,用來區分經過容器來獲取FactoryBean產生的對象和獲取FactoryBean自己。
2.舉例來講,若是myJndiObject是一個FactoryBean,那麼使用&myJndiObject獲得的是FactroyBean,而不是myJndiObject這個FactoryBean產生出來的對象。
3.關於具體的FactoryBean的設計和實現模式
4.注意,理解上面這段話須要很好地區分FactoryBean和BeanFactory這兩個在Spring中使用頻率很高的類,它們在拼寫上很是類似。
5.一個是Factory,也就是IoC容器或對象工廠;一個是Bean。
6.在Spring中,全部的Bean都是由BeanFactory(也就是IoC容器)來進行管理的。
7.但對FactoryBean而言,這個Bean不是簡單的Bean,而是一個能產生或者修飾對象生成的工廠Bean,它的實現與設計模式中的工廠模式和修飾器相似。
四.BeanFactory容器的設計原理
以XmlBeanFactory爲例,最底層實現,與應用上下文相比,顯著的特色是:它能提供最基本的IoC容器功能.
1.繼承DefaultListableBeanFactory擁有默認完成的IoC容器功能外,還能夠讀取Xml文件定義BeanDefinition.
2.XmlBeanFactory源碼實現讀取Xml文件功能
@Deprecated @SuppressWarnings({"serial", "all"}) public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); } /** * 總結分析具體的實現步驟: * 1.建立IoC配置文件的抽象資源resource,資源包含了BeanDefinition. * 2.建立BeanFactory,這裏使用DefaultListableBeanFactory. * 3.建立BeanDefinition讀取器,這裏使用XmlBeanDefinitionReader,經過回調配置給BeanFactory. * 4.從定義好的資源位置讀入配置信息,由XmlBeanFactory完成具體的解析過程.最終創建起IoC容器. * * 編程式實現 ClassPathResource res = new ClassPathResource("beans.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(res); }
五ApplicationContext的應用場景
appicationContext是一個高級形態的IoC容器,在BeanFactory的基礎上添加了額外的功能,從而具有了新特性:
六.ApplicationContext容器的設計原理
如:以FileSystemXmlApplicationContext來講明ApplicationContext的設計原理.
ApplicationContext應用上下文的主要功能已經在FileSystemXmlApplicationContext的基類AbstractXmlApplicationContext中實現,它只須要實現和它自身設計相關的兩個功能便可.