Spring框架的作用主要就是帮助业务开发人员把众多的业务类解耦。
1)通过配置(或注解)的方式可以使代码目录结构更灵活好管理。
2)通过全局上下文+构建工厂的方式统一管理bean,从而业务逻辑开发的代码更聚焦,使用bean也简便。
3)大多情况下bean作为单例存放在map中可以作为缓存提高效率同时也节约了资源。
关于IOC思想
就是设计模式中的依赖倒置原则,通俗点理解就是通过一种约定来简化某些繁琐的代码,父模块1不需要关注子模块2的实现细节,只要调用过程中传进来的对象或者参数复合约定,就可以达到正常运转。通过这种思想使模块间分工明确,耦合度降低。对于java这种强类型语言就表现为接口,而javascript要表现这种约定可能就要体现在文档上,最终目的都是一样的。
关于spring容器
有的说是BeanFactory,有的说是ApplicationContext,二者都是接口,后者继承了前者。
从设计过程来看,开始可能只需要一个map<Bean>就够了,随着框架的完善,想管理这个map需要加入工厂模式,建造者模式,还需要很多辅助的配置信息也需要管理,到最后自然就演变成了一个应用上下文对象。
关于Spring容器的创建过程
使用的是一个叫ClassPathXmlApplicationContext的最终实现类,通过获取配置文件,解析配置文件,生成标准化的BeanDefinition,最终初始化好Bean实例
在这个过程中有个重要的方法叫refresh,“刷新”的意思是销毁原bean,重建新的bean,要想创建新的bean就必须调用refresh,为什么要这么做?其实也好理解,原有的bean都是单例维护的,直接销毁的方式避免了缓存问题(比如热加载过程)
其中,BeanDefinition是SpringBean的描述对象,是通过解析Bean配置文件得到的对象,用于给BeanFactory创建Bean,这样BeanFactory才能统一的标准化的生产Bean实例,就好比车间根据图纸生产产品。
refresh的过程大体如下
-> refresh()
-----> obtainFreshBeanFactory() 返回一个BeanFactory,根据配置文件解析出BeanDefinition (Bean的描述信息对象,BeanDefinition会保存到专门的一个map中去),注册到BeanFactory中。
---------> refreshBeanFactory()
-------------> destoryBeans() 销毁原有Bean
-------------> closeBeanFactory() 销毁原有BeanFactory
-------------> createBeanFactory() 创建新的BeanFactory
-------------> customizeBeanFactory(beanFactory) 设置BeanFactory的配置属性:是否允许覆盖;是否允许循环依赖
-------------> loadBeanDefinitions(beanFactory) 把BeanDefinition加载到BeanFactory中
-----------------> 上述方法最终会通过XmlBeanDefinitionReader这个实现类的loadBeanDefinitions(encodedResource)方法来执行,参数是xml文件的描述对象。其中需要注意的是encodedResource是用ThreadLocal去存放的。
----------------------> doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 开始创建BeanDefinition,先把resource信息转化为Document对象然后交给下面的方法去处理
--------------------------> registerBeanDefinitions(doc, resource) 注册BeanDefinition
------------------------------> parseBeanDefinitions(root, this.delegate) 开始解析dom遍历dom结构,针对各种类型标签处理,其中遇到bean标签会如下处理
----------------------------------> parseBeanDefinitionElement() 简单来说就是读取标签属性,生成AbstractBeanDefinition,用于封装到BeanDefinitionHolder中去并返回
----------------------------------> BeanDefinitionReaderUtils.registerBeanDefinition(holder, getReaderContext().getRegistry()) 注册BeanDefinition,规则是beanName作为key,BeanDefinition为value。
具体注册流程:
第一次直接把BeanDefinition放到beanDefinitionMap中去,key为beanName,同时把beanName也放到beanDefinitionNames中去,这是一个ArrayList。
如果不是第一次则根据beanName先取BeanDefinition,如果之前配置不允许覆盖,则抛异常,允许则看是否有其他bean先初始化,如果有则使用synchronized同步add到对应map和list中去。
至此我们了解到BeanDefinition会被注册到一个map中去,这个map就是BeanFactory的一个属性,从而就把BeanDefinition注册到了BeanFactory中。
上述流程基本做的都是后勤工作,下面开始真正的创建Bean实例
-----> finishBeanFactoryInitialization(beanFactory) 初始化所有bean,最终通过反射被初始化到一个map(SingletonsPool)中去管理。
这个思路很简单,但是由于框架需要扩展一些功能,比如第三方库,aop支持,生命周期相关的扩展等,代码就会变得复杂起来,暂时留待以后详细梳理。
20210722 Spring容器初始化到bean销毁过程
- 创建Spring容器:就是创建BeanFactory的过程
- 加载xml或者注解:通过io流加载配置文件,并转化成document对象的过程。
- 创建BD的过程:解析document对象创建BeanDefinition对象。然后如果Bean实现了BeanFactoryPostProcessor这个接口,spring会自动调用实现的postProcessBeanFactory方法,对BeanDefinition的自定义扩展,得到最终版的BD。
以下开始是Bean生命周期 - 实例化Bean:通过java反射或者cglib创建,开辟了内存空间。bean有方法覆盖的时候才会执行cglib创建。
- 执行初始化赋值:
如果bean实现了BeanPostProcessor 的 postProcessBeforeInitialization 方法,就执行对应apply方法执行回调;
中间是执行处理init-method配置或者实现了InitializingBean接口,执行相关回调;
最后如果bean实现了BeanPostProcessor的postProcessAfterInitialization方法,执行对应apply方法执行回调。 - bean销毁。
网友评论