Spring IOC:Spring IOC 的根本基礎原理在哪裏?

spring框架的基礎核心和起點毫無疑問就是IOC,IOC做爲spring容器提供的核心技術,成功完成了依賴的反轉:從主類的對依賴的主動管理反轉爲了spring容器對依賴的全局控制。spring

這樣作的好處是什麼呢?框架

固然就是所謂的「解耦」了,可使得程序的各模塊之間的關係更爲獨立,只須要spring控制這些模塊之間的依賴關係並在容器啓動和初始化的過程當中將依據這些依賴關係建立、管理和維護這些模塊就好,若是須要改變模塊間的依賴關係的話,甚至都不須要改變程序代碼,只須要將更改的依賴關係進行修改便可,spring會在再次啓動和初始化容器的過程當中使得這些新的依賴關係從新創建符合新需求的模塊,在這個過程當中,須要注意的是代碼自己不須要體現對於模塊具體依賴情形的聲明而只須要定義其所需模塊的接口,因此這是一種典型的面向接口思想,同時最好將依賴關係以配置文件或者註解的形式表述出來,相關的spring處理類會根據這些外部的配置文件組裝模塊,或者掃描註解調用內部的註解處理器組裝模塊,以此完成IOC的過程。ide

IOC的目的是稱爲DI的依賴注入,經過IOC技術,最終容器將幫助咱們完成模塊間的依賴注入。測試

另外,最終的一點是,在spring IOC的過程當中,咱們必須始終清楚以上這條主線,即時語法和類的結構再複雜,可是其做用和目的都是同樣的:就是經過依賴描述的配置文件這一裝配「圖紙」去完成模塊的「組裝」,複雜的語法只是完成這一目的的手段罷了。ui

所謂的IOC原型,爲了展現最簡單的IOC原理圖,咱們不妨作一個徹底簡單的原型來講明這個過程:this

首先是咱們定義的幾個模塊,包括主模塊和兩個接口定義的依賴模塊:code

class MainModule{
    private DependModuleA moduleA;
    private DependModuleB moduleB;
    public DependModuleA getModuleA() {
        return moduleA;
    }
    public void setModuleA(DependModuleA moduleA) {
        this.moduleA = moduleA;
    }
    public DependModuleB getModuleB() {
        return moduleB;
    }
    public void setModuleB(DependModuleB moduleB) {
        this.moduleB = moduleB;
    }
    
}

interface DependModuleA{
    public void funcFromModuleA();
}

interface DependModuleB{
    public void funcFromModuleB();
}

class DependModuleAImpl implements DependModuleA{

    @Override
    public void funcFromModuleA() {
        System.out.println("This is func from Module A");
    }
    
}

class DependModuleBImpl implements DependModuleB{

    @Override
    public void funcFromModuleB() {
        System.out.println("This is func from Module B");
    }
    
}

若是咱們不採用IOC,而是依靠主模塊自己去控制其依賴模塊的建立,那麼會是這樣的:xml

public class SimpleIOCDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        MainModule mainModule = new MainModule();
        mainModule.setModuleA(new DependModuleAImpl());
        mainModule.setModuleB(new DependModuleBImpl());
        mainModule.getModuleA().funcFromModuleA();
        mainModule.getModuleB().funcFromModuleB();
    }
}

這是咱們通過簡化定義的IOC容器原型,容器在啓動後初始化的時候會讀取用戶寫入的配置文件,這裏咱們以簡單的properties配置文件爲例,只有當用戶調取getBean方法的時候纔會真正地按照配置文件組裝加載相應的bean,在咱們定義的容器原型內部維護着一個用於保存裝配好的bean 的map,若是在其中有知足要求的bean的話就不須要再新建了:接口

class SimpleIOCContainer{
    private Properties properties = new Properties();
    private Map<String, Object> moduleMap = new HashMap<>();
    {
        try {
            properties.load(new FileInputStream(new File("SimpleIOC.properties")));
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    public Object getBean(String moduleName) throws ClassNotFoundException {
        Object instanceObj;
        if(moduleMap.get(moduleName)!=null){
            System.out.println("return old bean");
            return moduleMap.get(moduleName);
        }
        System.out.println("create new bean");
        String fullClassName = properties.getProperty(moduleName);
        if(fullClassName == null)
            throw new ClassNotFoundException();
        else{
            Class<? extends Object> clazz = Class.forName(fullClassName);
            try {
                instanceObj = clazz.newInstance();
                instanceObj = buildAttachedModules(moduleName,instanceObj);
                moduleMap.put(moduleName, instanceObj);
                return instanceObj;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    private Object buildAttachedModules(String modulename , Object instanceObj) {
        Set<String> propertiesKeys = properties.stringPropertyNames();
        Field[] fields = instanceObj.getClass().getDeclaredFields();
        for (String key : propertiesKeys) {
            if(key.contains(modulename)&&!key.equals(modulename)){
                try {
                    Class<? extends Object> clazz = Class.forName(properties.getProperty(properties.getProperty(key)));
                    for (Field field : fields) {
                        if(field.getType().isAssignableFrom(clazz))
                            field.set(instanceObj, clazz.newInstance());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                
            }
        }
        return instanceObj;
    }
}

這是咱們使用properties配置文件寫成的依賴關係配置文件,這個配置文件是咱們裝配模塊的「圖紙」,這裏的語法個是徹底是咱們定義的,在真實的spring IOC容器中,爲了表達更爲複雜的依賴邏輯,會使用更爲發達的xml格式配置文件或者更新的註解配置,依靠註解處理器來完成圖紙的解析:get

mainModule=com.rocking.demo.MainModule
mainModule.moduleA=moduleA
mainModule.moduleB=moduleB
moduleA=com.rocking.demo.DependModuleAImpl
moduleB=com.rocking.demo.DependModuleBImpl

這是測試代碼,能夠看到的是咱們能夠完整的經過咱們定義的IOC容器獲取到符合要求的模塊,同時也能夠發現咱們定義的容器能夠爲咱們維護這些bean,當有bean已經組裝建立出來以後就不須要再建立了。

public class SimpleIOCDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        SimpleIOCContainer container = new SimpleIOCContainer();
        DependModuleA moduleA = (DependModuleA) container.getBean("moduleA");
        moduleA.funcFromModuleA();
        DependModuleB moduleB = (DependModuleB) container.getBean("moduleB");
        moduleB.funcFromModuleB();
        MainModule mainModule = (MainModule) container.getBean("mainModule");
        mainModule.getModuleA().funcFromModuleA();
        mainModule.getModuleB().funcFromModuleB();
        container.getBean("mainModule");
    }
}

這就是我依據IOC的基本思想建立的IOC容器原型,spring IOC雖然語法複雜,可是說到底完成的任務在覈心上都是同樣的,所謂的「萬變不離其宗」。

相關文章
相關標籤/搜索