最近一直在和容器打交道,甚至前面的博文,咱們也介紹了Spring的IoC的原理以及源碼,可是回頭看看,duang~ duang~的,仍是深了,不夠通俗易懂,不夠深刻淺出。因爲以上緣由吧,從這篇博客開始,咱們從一個簡單的容器開始,一步步的重構,最後實現一個基本的Spring框架的雛形,爲了幫助咱們更加深刻的理解Spring的IoC的原理和源碼。java
容器
相信你們對容器並不陌生,它是生活中很是常見的物品,容器用來包裝和裝載物品的貯存器(如箱、罐、壇等等),可是在編程中什麼容器呢?咱們先看一下百科的解釋:sql
---------------------------------------------------------------------------------------------------------------------------------------------------------編程
容器能夠管理對象的生命週期、對象與對象之間的依賴關係,您可使用一個配置文件(一般是XML),在上面定義好對象的名稱、如何產生(Prototype 方式或Singleton 方式)、哪一個對象產生以後必須設定成爲某個對象的屬性等,在啓動容器以後,全部的對象均可以直接取用,不用編寫任何一行程序代碼來產生對象,或是創建對象與對象之間的依賴關係。框架
---------------------------------------------------------------------------------------------------------------------------------------------------------ide
看見上面的解釋,第一感受就是什麼玩意?說白了,容器就是一個專門用來管理對象的模塊。它負責建立對象,管理對象的依賴關係,管理對象的生命週期等等,相似這樣的模塊就叫容器。spa
運行在容器中的對象也稱爲組件,它們必須遵循容器定義的規範。.net
普通實現
咱們理解了容器以後,下面咱們從一個簡單的實例開始。先看一下代碼:設計
Service層:component
[java] view plain copy對象
- public interface Service {
- public void serviceMethod();
- }
[java] view plain copy
- import com.tgb.container.dao.Dao;
- import com.tgb.container.dao.impl.Dao4MySqlImpl;
- import com.tgb.container.service.Service;
-
- public class ServiceImpl implements Service {
- //實例化Dao實現
- private Dao dao = new Dao4MySqlImpl();
-
- @Override
- public void serviceMethod() {
- //調用Dao實現的方法
- dao.daoMethod();
- }
- }
Dao層:
[java] view plain copy
- public interface Dao {
- public void daoMethod();
- }
[java] view plain copy
- import com.tgb.container.dao.Dao;
-
- public class Dao4MySqlImpl implements Dao {
- public void daoMethod(){
- System.out.println("Dao4MySqlImpl.daoMethod()");
-
- }
- }
[java] view plain copy
- import com.tgb.container.dao.Dao;
-
- public class Dao4OracleImpl implements Dao {
- public void daoMethod(){
- System.out.println("Dao4OracleImpl.daoMethod()");
-
- }
-
- }
客戶端:
[java] view plain copy
- import com.tgb.container.service.Service;
- import com.tgb.container.service.impl.ServiceImpl;
-
- public class Client {
- public static void main(String[] args) {
- //實例化Service實現
- Service service = new ServiceImpl();
- //調用Service實現的方法
- service.serviceMethod();
- }
- }
這段代碼的運行結果,你們一眼就能看出來,以下:
Dao4MySqlImpl.daoMethod()
UML類圖以下:
從上圖咱們能夠發現,ServiceImpl不只依賴Dao層接口,並且還依賴Dao層實現,顯然違背了面向對象的基本設計原則,依賴倒轉原則:抽象不該該依賴細節,細節應該依賴與抽象,說白了,就是針對接口編程,不要對實現編程。
藉助容器
下面咱們使用容器來將依賴實現的關係去掉。
Container類:
[java] view plain copy
- import java.util.HashMap;
- import java.util.Map;
-
- import com.tgb.container.dao.Dao;
- import com.tgb.container.dao.impl.Dao4MySqlImpl;
- import com.tgb.container.service.Service;
- import com.tgb.container.service.impl.ServiceImpl;
-
- public class Container {
- //定義一個map結構的對象
- private static Map<String, Object> components;
-
- private Container() {
- }
-
- /**
- * 初始化容器
- */
- public static synchronized void init() {
- if (components == null) {
- components = new HashMap<String, Object>();
- //寫一個讀配置文件的類,根據讀取的配置文件,反射對應的類
- //反射好類後進行 依賴管理,往對應的屬性上注入相應的類
- //客戶端建立新類的時候把容器建立好的類付給新類
-
- Dao dao4Mysql = new Dao4MySqlImpl();
- components.put("dao4Mysql", dao4Mysql);
-
- Service service = new ServiceImpl();
- components.put("service", service);
-
- }
- }
-
- /**
- * 查找組件
- *
- * @param id
- * @return
- */
- public static Object getComponent(String id) {
- return components.get(id);
- }
-
- }
修改ServiceImpl類:
[java] view plain copy
- import com.tgb.container.Container;
- import com.tgb.container.dao.Dao;
- import com.tgb.container.service.Service;
-
- public class ServiceImpl implements Service {
- //從容器查找響應的對象
- private Dao dao = (Dao) Container.getComponent("dao4Mysql");
-
- @Override
- public void serviceMethod() {
- dao.daoMethod();
- }
- }
客戶端:
[java] view plain copy
- import com.tgb.container.Container;
- import com.tgb.container.service.Service;
-
- public class Client {
- public static void main(String[] args) {
- //容器初始化,這個能夠用filter完成,只需在整個項目中初始化一次
- Container.init();
-
- //從容器中查找接口
- Service service =(Service)Container.getComponent("service");
- //調用Service實現的方法
- service.serviceMethod();
- }
- }
此時的UML類圖以下:
對比兩張類圖,咱們能夠發現,容器給咱們帶來了優勢,同時也帶來了缺點。
優勢:
此時的Service層再也不依賴Dao層實現,而把這種對實現的依賴交給了容器。
缺點:
可是咱們卻發現,ServiceImpl依賴了Container容器類,使得組件不能脫離容器獨立存在,顯然,這是一種「侵入式」的管理。