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虽然语法复杂,可是说到底完成的任务在核心上都是同样的,所谓的“万变不离其宗”。

相关文章
相关标签/搜索