Spring系列之IOC的原理及手動實現

目錄

導語

Spring是一個分層的JavaSE/EE full-stack(一站式) 輕量級開源框架。也是幾乎全部Java工做者必需要掌握的框架之一,其優秀的設計思想以及其代碼實現上的藝術也是咱們須要掌握的。要學習Spring,除了在咱們的項目中使用以外,也須要對它的源碼進行研讀,可是Spring的實現涵蓋的知識不少,在加上其中的類的數量也是很是的多,在咱們閱讀源碼時可能會在幾十個類之間穿插閱讀,頗有可能一不當心就致使思惟混亂。有鑑於此,我這裏先對Spring中的幾個重要的模塊進行一個手動的簡易實現,一是熟悉這些模塊的原理,同時也是仿造Spring中的結構來對後面閱讀源碼打下基礎。html

IOC(Inversion of Control)

Inversion of Control即控制反轉,其意思是將咱們以前由客戶端代碼來建立的對象交由IOC容器來進行控制,對象的建立,初始化以及後面的管理都由IOC完成。設計模式

IOC的好處

  1. 解耦:IOC的出現解決了類於類之間的耦合,咱們在Web開發的Servlet時代,若是一個Servlet須要依賴另外一個類的某些實現,那麼咱們須要在當前類對依賴的類進行建立和初始化,若是其餘類也依賴了這個類,那也須要進行建立和初始化,而交給了IOC來管理的話,那麼在須要的時候只需向IOC進行申請,而不須要重複的建立和初始化。固然,IOC也容許每次都從新建立一個新的對象。
  2. 方便與AOP進行配合:AOP也是一個使用十分頻繁的功能,經過IOC能夠十分方便的與AOP進行配合。

IOC中設計的設計模式

工廠模式。IOC容器來負責建立管理類實例對象,在須要時向IOC進行申請,從IOC中獲取。因此IOC容器也稱爲bean工廠。併發

工廠模式是一種比較簡單易懂的設計模式,這裏就不在介紹了,若是有須要的能夠看看這個:工廠模式框架

IOC的手動實現

Bean定義

IOC的主要的功能即是對Bean進行管理,包括建立、初始化、管理以及銷魂的工做。首先咱們面對的問題就是咱們怎麼讓IOC可以建立一個Bean?爲了建立Bean咱們須要提供一些什麼?ide

如何建立Bean

在不手動經過new關鍵字建立的狀況下建立類實例的對象方法有兩種:學習

  1. 反射:經過反射的方法能夠建立類的實例:clazz.getClass().newInstance();
  2. 工廠模式:工廠模式可讓咱們在不接觸實例類的狀況下建立出實例。
public class PersonFactory{
    public Person getPerson(){
        return new Person();
    }
}
爲了建立Bean咱們須要提供什麼

經過分析上面的兩種方法能夠輕鬆得出答案。測試

對於反射的方式咱們僅需提供實例的Class對象。this

對於工廠方法咱們須要提供的就是建立該類的工廠名(factoryName)和方法名(methodName);設計

除了建立bean還須要作些什麼

IOC容器是對bean的整個生命週期進行管理,除了建立以外還須要對bean進行初始化,以及不須要時對bean進行銷燬的工做(如釋放資源等)。因此咱們還須要提供初始化和銷燬等操做。code

到這裏建立bean須要的基本分析完了,看類圖:

BeanDefinition

Bean工廠

Bean的定義解決了,可是這個bean定義以及建立好的Bean實例放在哪裏呢,咱們須要一個統一的地方來存放這些東西以方便咱們要用的時候方便取。

咱們定義一個Bean工廠來存放bean,在須要的時候懂bean工廠中取便可,bean工廠對外提供的也僅僅是一個獲取bean的方法便可,因爲bean的類型不定,因此返回值定位Object。

BeanFactory

註冊Bean定義

到了如今咱們有了建立bean的Bean定義,有了存放和管理bean的Bean工廠,如今須要考慮的事怎麼來聯繫這兩個類,咱們還須要另一個接口,接口的功能是讓咱們能註冊和獲取bean定義,這裏咱們經過beanName來區分不一樣的bean。

BeanDefinitionRegistry

代碼實現

到這裏咱們實現一個簡易的IOC容器的須要的東西基本準備完成了,看下基本類圖:

類關係

基本代碼實現:

DefaultBeanDefinition:

public class DefaultBeanDefinition implements BeanDefinition{

    private Class<?> clazz;

    private String beanFactoryName;

    private String createBeanMethodName;

    private String staticCreateBeanMethodName;

    private String beanInitMethodName;

    private String beanDestoryMethodName;

    private boolean isSingleton;

    // setter
    

    public void setSingleton(boolean singleton) {
        isSingleton = singleton;
    }

    @Override
    public Class<?> getBeanClass() {
        return this.clazz;
    }

    @Override
    public String getBeanFactory() {
        return this.beanFactoryName;
    }

    @Override
    public String getCreateBeanMethod() {
        return this.createBeanMethodName;
    }

    @Override
    public String getStaticCreateBeanMethod() {
        return this.staticCreateBeanMethodName;
    }

    @Override
    public String getBeanInitMethodName() {
        return this.beanInitMethodName;
    }

    @Override
    public String getBeanDestoryMethodName() {
        return this.beanDestoryMethodName;
    }

    @Override
    public String getScope() {
        return this.isSingleton?BeanDefinition.SINGLETION :BeanDefinition.PROTOTYPE;
    }

    @Override
    public boolean isSingleton() {
        return this.isSingleton;
    }

    @Override
    public boolean isPrototype() {
        return !this.isSingleton;
    }
}

DefaultBeanFactory:

public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {

    private Log log = LogFactory.getLog(this.getClass());

    //ConcurrentHashMap應對併發環境
    private Map<String, BeanDefinition> bdMap = new ConcurrentHashMap<>();

    private Map<String, Object> beanMap = new ConcurrentHashMap<>();

    @Override
    public void register(BeanDefinition bd, String beanName) {

        Assert.assertNotNull("beanName不能爲空 beanName", beanName);
        Assert.assertNotNull("BeanDefinition不能爲空", bd);

        if(bdMap.containsKey(beanName)){
            log.info("[" + beanName + "]已經存在");
        }

        if(!bd.validate()){
            log.info("BeanDefinition不合法");
        }

        if(!bdMap.containsKey(beanName)){
            bdMap.put(beanName, bd);
        }
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return bdMap.containsKey(beanName);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        if(!bdMap.containsKey(beanName)){
            log.info("[" + beanName + "]不存在");
        }
        return bdMap.get(beanName);
    }

    public Object doGetBean(String beanName) throws InstantiationException, IllegalAccessException {
        if(!beanMap.containsKey(beanName)){
            log.info("[" + beanName + "]不存在");
        }

        Object instance = beanMap.get(beanName);

        if(instance != null){
            return instance;
        }

        //不存在則進行建立
        if(!this.bdMap.containsKey(beanName)){
            log.info("不存在名爲:[" + beanName + "]的bean定義");
        }

        BeanDefinition bd = this.bdMap.get(beanName);

        Class<?> beanClass = bd.getBeanClass();

        if(beanClass != null){
            instance = createBeanByConstruct(beanClass);
            if(instance == null){
                instance = createBeanByStaticFactoryMethod(bd);
            }
        }else if(instance == null && StringUtils.isNotBlank(bd.getStaticCreateBeanMethod())){
            instance = createBeanByFactoryMethod(bd);
        }

        this.doInit(bd, instance);

        if(instance != null && bd.isSingleton()){
            beanMap.put(beanName, instance);
        }

        return instance;
    }

    private void doInit(BeanDefinition bd, Object instance) {
        Class<?> beanClass = instance.getClass();
        if(StringUtils.isNotBlank(bd.getBeanInitMethodName())){
            try {
                Method method = beanClass.getMethod(bd.getBeanInitMethodName(), null);
                method.invoke(instance, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 構造方法建立實例
     * @param beanClass
     * @return
     */
    private Object createBeanByConstruct(Class<?> beanClass) {
        Object instance = null;
        try {
            instance = beanClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }

    /**
     * 普通工廠方法建立實例
     * @param bd
     * @return
     */
    private Object createBeanByFactoryMethod(BeanDefinition bd) {
        Object instance = null;
        try {
            //獲取工廠類
            Object factory = doGetBean(bd.getBeanFactory());
            //獲取建立實例的方法
            Method method = factory.getClass().getMethod(bd.getCreateBeanMethod());
            //執行方法
            instance = method.invoke(factory, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }

    /**
     * 靜態方法建立實例
     * @param bd
     * @return
     */
    private Object createBeanByStaticFactoryMethod(BeanDefinition bd) {
        Object instance = null;
        try {
            Class<?> beanClass = bd.getBeanClass();
            //獲取建立實例的方法
            Method method = beanClass.getMethod(bd.getStaticCreateBeanMethod());
            instance = method.invoke(beanClass, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }

    @Override
    public Object getBean(String beanName) {
        if(!beanMap.containsKey(beanName)){
            log.info("[" + beanName + "]不存在");
        }
        return beanMap.get(beanName);
    }

    @Override
    public void close() throws IOException {
        Set<Map.Entry<String, BeanDefinition>> entries = bdMap.entrySet();
        for(Map.Entry<String, BeanDefinition>  entry: entries){
            BeanDefinition value = entry.getValue();
            String destoryMethodName = value.getBeanDestoryMethodName();
            try {
                Method method = value.getBeanClass().getMethod(destoryMethodName, null);
                method.invoke(value.getBeanClass(), null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

簡單測試一下:
實例bean:

public class User {

    private String name;

    private int age;

    //getter setter

    public void init(){
        System.out.println("init...");
    }

    public void destory(){
        System.out.println("destory...");
    }

}

工廠類:

public class TestFactory {
    public Object createMethod(){
        return new User();
    }

    public static Object staticCreateMethod(){
        return new User();
    }
}

測試類:

public class MySpringTest {

    static DefaultBeanFactory factory = new DefaultBeanFactory();

    @Test
    public void test() throws IllegalAccessException, InstantiationException {
        DefaultBeanDefinition bd = new DefaultBeanDefinition();
        bd.setClazz(User.class);
        bd.setSingleton(true);
        bd.setBeanFactoryName("TestFactory");
        bd.setCreateBeanMethodName("createMethod");
        bd.setStaticCreateBeanMethodName("staticCreateMethod");

        bd.setBeanInitMethodName("init");

        factory.register(bd, "user");

        System.out.println(factory.doGetBean("user"));
    }
}

小結

一個簡易的容器就這樣實現了,固然咱們這裏只是具有了基本的功能,實際上還差的遠,好比帶參數的bean的實例化等功能。可是IOC的基本原理已經表達出來了,後面咱們只需在這個基礎上添加新的功能便可。

相關文章
相關標籤/搜索