时间:2021-05-19
Spring IOC的原型
spring框架的基础核心和起点毫无疑问就是IOC,IOC作为spring容器提供的核心技术,成功完成了依赖的反转:从主类的对依赖的主动管理反转为了spring容器对依赖的全局控制。
这样做的好处是什么呢?
当然就是所谓的“解耦”了,可以使得程序的各模块之间的关系更为独立,只需要spring控制这些模块之间的依赖关系并在容器启动和初始化的过程中将依据这些依赖关系创建、管理和维护这些模块就好,如果需要改变模块间的依赖关系的话,甚至都不需要改变程序代码,只需要将更改的依赖关系进行修改即可,spring会在再次启动和初始化容器的过程中使得这些新的依赖关系重新建立符合新需求的模块,在这个过程中,需要注意的是代码本身不需要体现对于模块具体依赖情形的声明而只需要定义其所需模块的接口,所以这是一种典型的面向接口思想,同时最好将依赖关系以配置文件或者注解的形式表述出来,相关的spring处理类会根据这些外部的配置文件组装模块,或者扫描注解调用内部的注解处理器组装模块,以此完成IOC的过程。
IOC的目的是称为DI的依赖注入,通过IOC技术,最终容器将帮助我们完成模块间的依赖注入。
另外,最终的一点是,在spring IOC的过程中,我们必须始终清楚以上这条主线,即时语法和类的结构再复杂,但是其作用和目的都是一样的:就是通过依赖描述的配置文件这一装配“图纸”去完成模块的“组装”,复杂的语法只是完成这一目的的手段罢了。
所谓的IOC原型,为了展示最简单的IOC原理图,我们不妨做一个完全简单的原型来说明这个过程:
首先是我们定义的几个模块,包括主模块和两个接口定义的依赖模块:
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,而是依靠主模块本身去控制其依赖模块的创建,那么会是这样的:
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格式配置文件或者更新的注解配置,依靠注解处理器来完成图纸的解析:
mainModule=com.rocking.demo.MainModulemainModule.moduleA=moduleAmainModule.moduleB=moduleBmoduleA=com.rocking.demo.DependModuleAImplmoduleB=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虽然语法复杂,但是说到底完成的任务在核心上都是一样的,所谓的“万变不离其宗”。
Spring IOC 的具体过程
上回展示了IOC的大致实现的原型,那么在Spring框架中具体是怎么实现这个容器根据metadata元信息配置加载POJO的过程的呢?在整个Spring IOC容器的工作过程中有很多地方是设计地相当灵活的,供给使用者很多空间去完成自己的任务,而不是一味地只是完成容器的机械过程。
这是整个IOC容器工作过程的过程图:
1、容器启动阶段
(1)加载配置文件信息
(2)解析配置文件信息
(3)装配BeanDefinition
(4)后处理
首先配置文件或者注解等元信息和JavaBean的类信息被加载到IOC容器中,容器读取到xml格式的配置文件,这个配置文件是使用者声明的依赖关系和装配中需要特别关注的地方,是装配Bean的早期“外部图纸”,容器中的解析引擎可以把我们写入的文本形式的字符元信息解析成容器内部可以识别的BeanDefinition,可以把BeanDefinition理解成为类似反射机制的类结构,这个通过对JavaBean和配置文件进行分析得到的BeanDefinition获取了组装一个符合要求的JavaBean的基本结构,如果需要除了BeanDefinition之后还要对这个BeanDefinition再做修改的话则执行这个后处理,后处理一般是通过Spring框架内的BeanFactoryPostProcessor处理的。
我们仍然使用上次使用过的例子来说明这个BeanDefinition的运作原理:有三个bean,主模块MainModule和依赖模块DependModuleA,DependModuleB,前者依赖后面两个模块构成,在配置文件里我们一般会这么进行依赖的声明:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://.rocking.demo.ModuleC"> </bean></beans>从最终的结果我们可以看出,每次调用getBean方法得到的bean实例(包括因依赖关系生成的)都将被BeanPostProcessor获取进行前置和后置处理。
除了类似上面的BeanPostProcessor的办法对装配好的bean再做处理外,Spring还可以通过配置init-method和destroy-method来对bean的初始化和销毁过程设置回调函数,这些回调函数也还可以灵活地提供更改bean实例的机会。
整个Spring IOC的过程其实总体来说和我们自己写的IOC原型在本质上是一样的,只不过通过复杂的设计使得IOC的过程能够更灵活有效地提供给使用者更多的发挥空间,除此之外,Spring的IOC也在安全性、容器的稳定性、metadata到bean转换的高效性上做到了精美的设计,使得IOC这一Spring容器的基础得以稳固。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
java中Springtask定时任务的深入理解在工作中有用到springtask作为定时任务的处理,spring通过接口TaskExecutor和TaskSc
spring-ioc的使用IOC容器在很多框架里都在使用,而在spring里它被应用的最大广泛,在框架层面上,很多功能都使用了ioc技术,下面我们看一下ioc的
一、什么是Spring?Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架二、如何在程序中获取Spring配置的bean呢?方法一:在初
本文分享自华为云社区《手把手教你写一个springIOC容器》,原文作者:技术火炬手。spring框架的基础核心和起点毫无疑问就是IOC,IOC作为spring
1.Spring简介Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。2.Spring的优势1.方便解耦,简化开发:通过Spring提供