前兩天寫簡歷,寫了一句:精通Spring IoC容器。怎麼個精通法?仍是本身動手寫個IOC容器吧。java
什麼是IoC(Inversion of Control)?什麼是DI(Dependency Injection)?很少解釋,本身Google!但願你先明確幾個概念,該文章不作這方面的闡述,重點關注如何實現。我將用簡要的語言從需求,設計,代碼三方面來描述一個簡單的IoC容器,來講明IoC容器是如何幫咱們建立類的實例、如何實現依賴注入,最後會奉上一個完整的IoC容器實例。git
1、需求,實現一個IoC容器算法
一、需求描述:spring
二、圖中一些概念:編程
(1)服務元數據:一種是咱們的編譯好的類文件,即.class文件;另外一種是xml文件。你能夠理解爲spring的註解和xml兩種配置bean的方式。設計模式
(2)服務定義信息:由元數據轉換來的信息,即讀取bean中的註解或xml文件,獲取到的對象描述信息。緩存
(3)服務提供者:對象的實例。你能夠理解爲Spring中Bean的實例;數據結構
(4)服務定義信息存儲區:保存服務定義信息的地方;ide
(5)服務提供者實例緩存區:保存服務提供者的地方。工具
三、流程描述:
(1)建立容器:初始化容器,實質是初始化容器內部的工廠,而後讀取元數據,轉化爲服務定義信息,保存到服務定義信息存儲區;
(2)調用服務提供者A的方法:獲取該服務提供者A的服務定義信息,判斷是否有緩存,若是有,直接調用緩存中的A;若是沒有,據此實例化A,放入緩存,若發現A依賴其餘服務提供者B,則查找緩存,若是有,將緩存中的B注入A;不然實例化B,注入到A中,同時放入緩存。以此類推。
(3)上面兩個是核心流程,在此基礎上,擴展了幾個流程:
1)獲取全部服務提供者定義信息;
2)獲取全部服務提供者實例;
3)獲取某個服務提供者實例;
4)熱加載新的服務提供者。
2、設計,根據需求,以面向對象爲基礎,融合幾種設計模式來勾勒IOC容器。
注:因爲源碼較多,會佔很大篇幅,因此只給出了部分核心代碼實現,全部代碼見個人CSDN CODE,見文章末尾的說明。
一、UML,類圖
二、設計說明
從類圖能夠看出,嚴格按照面向接口的方式編程,鬆耦合的設計保證了可擴展性和靈活性。
我定義了一套實現IOC容器的規範,這套規範的直接表現就是一組接口及其關係,有沒有一點J2EE的感受。而後,我給出了各個接口的一個默認實現,也就是給出了一個容器的默認實現。其餘開發者既能夠所有個人默認實現或所有使用自定義實現,也能夠部分組件使用默認實現,部分組件實現自定義實現。
三、介紹接口與默認實現,即擴展點。
(1)Container接口及默認實現
核心代碼:
import com.tgb.Entity.BeanEntity; import com.tgb.data.IDataContext; /** * @Author : JiaLin * @Email : shan9liang@163.com * @Date : 2014/6/22 * @Description :容器的核心接口 */ public interface IContainer{ //獲取容器的某個服務提供者實例 public Object getBean(String name); //根據服務提供者名稱,服務名稱,參數來獲取容器提供的服務 //由三者肯定一個惟一的服務。 public Object getService(String beanName,String serviceName,Object... args); //獲取容器全部服務描述信息 public IDataContext getBeanDefinitionContext(); //獲取容器中某個服務提供者的描述信息 public BeanEntity getBeanDefinition(String name); //獲取容器中全部服務提供者實例的緩存 public IDataContext getBeanCacheContext(); //熱加載新的服務提供者 public void initContainerService(String resource); }
說明:Container採用外觀模式,充當Factory的外觀層。Container能夠自定義實現,這是擴展點一。並且使用了工廠模式和策略模式實現容器內部具體工廠的動態加載。
(2)Factory接口與默認實現
核心代碼:
import com.tgb.Entity.BeanEntity; import com.tgb.data.IDataContext; import com.tgb.handler.HandlerDecorator; import java.io.Serializable; /** * @Author : JiaLin * @Email : shan9liang@163.com * @Date : 2014/6/22 * @Description : 抽象的服務工廠,定義處理服務的算法骨架,具體由其子類實現。 */ //使用模板方法模式定義算法的骨架,具體實現有相應的子類去作。 public abstract class AbstractBeanFactory implements IBeanFactory, Serializable { //----------組件初始化----------begin----- protected IDataContext beanDefinitionContext;//服務描述信息的存儲區 protected IDataContext beanCacheContext; //服務提供者實例的緩存區 protected HandlerDecorator handlerDecorator;//轉換器(元數據到服務描述信息) //設置服務描述信息的存儲區 public abstract void setBeanDefinitionContext(String beanDefinitionContextName, String resource); //設置服務提供者實例的緩存區 public abstract void setBeanCacheContext(String beanCacheContextName); //設置轉換器(元數據到服務描述信息) public abstract void setHandler(String defaultHandler, String handlerName); @Override //模板方法 //註冊服務組件,初始化服務描述信息 public final void registerBeanDefinition(String resource, String cacheContext, String definitionContext, String defaultHandler, String customHandler) { this.setHandler(defaultHandler, customHandler); this.setBeanCacheContext(cacheContext); this.setBeanDefinitionContext(definitionContext, resource); } //----------組件初始化----------end----- //----------服務提供者的生命週期-----begin-------- //獲取某個服務提供者的服務描述信息 public abstract BeanEntity getBeanDefinition(String name); //檢查該服務提供者的實例是否有緩存 public abstract boolean containsBeanCache(String name); //從緩存中獲取服務提供者的實例 public abstract Object getBeanCache(String name); //建立服務提供者 public abstract Object creatBean(BeanEntity beanEntity); //將服務提供者實例註冊到緩存 public abstract Object regiterBeanCache(String name, Object obj); //----------服務提供者的生命週期-----end-------- @Override //模板方法 //獲取服務提供者實例 public final Object getBean(String name) { //獲取某個Bean的定義 BeanEntity beanEntity = getBeanDefinition(name); //判斷這個Bean是否已經加載到緩存,若是有,直接返回 if (containsBeanCache(name)) { return getBeanCache(name); } //建立bean的實例 Object beanObject = this.creatBean(beanEntity); //註冊到緩存 regiterBeanCache(name, beanObject); //返回bean的實例 return beanObject; } //獲取全部的服務描述信息 public abstract IDataContext getBeanDefinitionContext(); //獲取全部的服務實例緩存信息 public abstract IDataContext getBeanCacheContext(); }
說明:AbstractBeanFactory採用模板方法模式,AbstractBeanFactory中定義了初始化服務定義信息和獲取服務提供者實例兩個模板方法,定義了算法的骨架。模板方法依賴的方法的實現交給子類去完成,這裏交給DefaultBeanFactory完成。能夠實現本身的BeanFactory,這是擴展點二。
(3)DataContext的接口及實現
核心代碼:
import java.util.Map; /** * @Author : JiaLin * @Email : shan9liang@163.com * @Date : 2014/6/22 * @Description :抽象的數據存儲接口 */ public interface IDataContext { public void initData(Map<String,Object> map); public void set(String name,Object obj); public Object get(String name); public Map<String,Object> getAll(); }
說明:IDataContext定義了存儲區域應該有的方法,兩個實現,DefaultBeanDefinitionContext是服務提供者描述信息存儲的默認實現;DefaultBeanCacheContext是服務提供者實例存儲的默認實現。能夠自定義存儲區實現,這是擴展點三。
(4)Handler接口及實現
核心代碼:
import java.util.Map; /** * @Author : JiaLin * @Email : shan9liang@163.com * @Date : 2014/6/23 * @Description : 抽象的處理器裝飾者 */ //使用裝飾者模式,能夠動態添加功能(這裏是動態添加元數據處理器) //例如要擴展Annotation就須要本身擴展處理器,或者擴展xml處理器等等 public abstract class HandlerDecorator implements IHandler{ protected IHandler handler; public void setHandler(IHandler handler){ this.handler=handler; } @Override public Map<String, Object> convert(String string) { if(handler!=null) { return handler.convert(string); } return null; } }
說明:這裏採用了一個裝飾者模式,默認提供了一個註解裝飾者DefaultAnnotationHandler,來把元數據中註解信息轉換爲服務提供者定義信息。其餘開發者可繼承HandlerDecorator,來實現本身的裝飾者,例如把xml信息轉換爲服務提供者定義信息的Xmlhandler。工廠會依次實現這些裝飾者解析元數據。這是擴展點四。
(5)Annotation
核心代碼:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @Author : JiaLin * @Email : shan9liang@163.com * @Date : 2014/6/22 * @Description :用來標註服務的提供者 */ @Retention(RetentionPolicy.RUNTIME) @Target( { ElementType.FIELD, ElementType.TYPE }) public @interface Bean { String name(); }
說明:這裏提供了三個註解來描述服務提供者的元數據,handler據此將元數據轉換爲服務提供者定義信息。其餘開發者可擴展該Annotation,實現本身的Annotation,而後自定義解析的handler,重寫factory的createBean方法便可。這是擴展點五。
(5)定義數據結構,存儲服務定義信息
import java.util.List; /** * @Author : JiaLin * @Email : shan9liang@163.com * @Date : 2014/6/22 * @Description :服務提供者描述信息載體,其數據結構以下: * * BeanEntity * * name type List * @bean註解名 Bean類型 ServicEntity的arrayList * ServiceEntity…… * * name value List * @Service註解名 方法名 ParamEntity的ArrayList * ParamEntity…… * name value * @param註解名 參數類型 */ public class BeanEntity { private String name; //服務提供者名 private String type; //服務提供者實例的類型 private Object value; //服務提供者實例 private List<ServiceEntity> serviceEntityList; //服務提供者提供的全部服務 public BeanEntity(){} public BeanEntity(String name,String type) { this.name=name; this.type=type; } //省略get,set方法 }
說明:這是java反射的工具類,封裝了一些反射經常使用方法。
(7)熱加載監聽器
說明:這個監聽器,將監聽某個位置,若是加入新的服務提供者元數據,將被容器熱加載。
3、全部代碼
一、上面介紹了需求,設計,以及核心代碼,若是依然不過癮,那來看看所有代碼吧。
我已將這個小項目開源,託管到CSDN CODE 公有項目,項目首頁:
https://code.csdn.net/shan9liang/ioccontainer
二、你們能夠幫着改進,也能夠下載查看,還有不少改進的地方,最近工做繁忙,有空會持續更新,歡迎提出寶貴意見。