Spring#IOC#refresh#obtainFreshBeanFactory源码
2021-11-05 18:24:55 0 举报
Spring#IOC#refresh#obtainFreshBeanFactory解析了整个过程,整个过程有点长,所以要耐心点看完,关键点都在后面。
作者其他创作
大纲/内容
javax.servlet.ServletContextListener
1.当前正在加载的EncodedResource
web.xml
AbstractRefreshableApplicationContext#refreshBeanFactory
需要另外一个文件来解析
DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
ContextLoaderListener#contextInitialized
接口ConfigurableApplicationContext#refresh
return getRegistry().getBeanDefinitionCount() - countBefore;
XmlBeanDefinitionReader#doLoadBeanDefinitions
profile 属性主要用于多环境开发
ContextLoader#configureAndRefreshWebApplicationContext
刷新 BeanFactory由AbstractRefreshableApplicationContext实现
1.根据inputSource和resource加载XML文件,并封装成Document
loadBeanDefinitions(beanFactory);
该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中
2.2 根据Resource,加载Bean的定义
总结:创建一个新的 BeanFactory:DefaultListableBeanFactory。根据 web.xml 中 contextConfigLocation 配置的路径,读取 Spring 配置文件,验证配置文件的内容,并封装成 Resource。根据 Resource 加载 XML 配置文件,并解析成 Document 对象 。拿到 Document 中的根节点,遍历根节点和所有子节点。
自定义命名空间,则走 delegate.parseCustomElement(ele) 方法进行解析,例如常见的: <context:component-scan/>、<aop:aspectj-autoproxy/>。
2.1 根据路径拿到该路径下所有符合的配置文件,并封装成Resource
int countBefore = getRegistry().getBeanDefinitionCount();
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
2.创建一个新的BeanFactory
wac.refresh();
不为空
int loadCount = loadBeanDefinitions(resources);
3.1 根据Resource,加载Bean的定义
5.加载 bean 定义(方法以do开头,真正处理的方法)
XmlBeanDefinitionReader#loadBeanDefinitions(Resource)
3.拿到Resource的inputStream将inputStream封装成org.xml.sax.InputSource
AbstractBeanDefinitionReader#loadBeanDefinitions(String)
为空
接口AbstractRefreshableApplicationContext#loadBeanDefinitions
拿到刷新后的 BeanFactory
3.只能通过绝对URL加载单个资源
2.处理profile属性
XmlBeanDefinitionReader#createBeanDefinitionDocumentReader
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource)
XmlWebApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)
DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
ContextLoader#initWebApplicationContext
createReaderContext(resource)
1.根据inputSource和resource加载XML文件,并封装成Document
3.加载 bean 定义。
Tomcat
解析 bean 定义的核心部分,这边会遍历 root 节点(正常为 <beans> 节点)下的所有子节点,对子节点进行解析处理。
否
int loadCount = loadBeanDefinitions(resource);
可以在配置文件中同时写上多套配置来适用于开发环境、测试环境、生产环境,这样可以方便的进行切换开发、部署环境,最常用的就是更换不同的数据库。
2.记录统计前BeanDefinition的加载个数
BeanDefinitionDocumentReader#registerBeanDefinitions
1.判断是否已经存在 BeanFactory,如果存在则先销毁、关闭该 BeanFactory
1.为指定BeanFactory创建XmlBeanDefinitionReader
configLocations属性是否为空
返回 configLocations 的值
上面提到的“加载到 BeanFactory 中”的内容主要指的是以下3个缓存:beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合。beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射。aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。
obtainFreshBeanFactory() 方法
3.createReaderContext:根据resource创建一个XmlReaderContext
常见的,如果解析到<context:component-scan base-package=\"com.joonwhee.open\" /> 注解时,会扫描 base-package 指定的目录,将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的 bean 定义也同样封装成 BeanDefinition,加载到 BeanFactory 中。
AbstractApplicationContext#refresh
5.返回本次加载的BeanDefinition个数
web.xml 中通过参数 spring.profiles.active 来配置
调用 getDefaultConfigLocations() 方法
XmlBeanDefinitionReader#registerBeanDefinitions
2.判断 resourceLoader 是否为 ResourcePatternResolver 的实例
4.解析并注册bean定义
1.校验root节点的命名空间是否为默认的命名空间(默认命名空间http://www.springframework.org/schema/beans)
这里会根据 resource 构建一个 XmlReaderContext,用于存放解析时会用到的一些上下文信息。其中 namespaceHandlerResolver 会创建默认的 DefaultNamespaceHandlerResolver,DefaultNamespaceHandlerResolver的handlerMappingsLocation 属性会使用默认的值 “META-INF/spring.handlers”,并且这边有个重要的属性 handlerMappingshandlerMappings 用于存放命名空间和该命名空间handler类的映射 handlerMappings 的值默认位于“META-INF/spring.handlers” 文件下,一般在我们定义自定义注解时需要用到。
1.使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
是
命名空间是否为 Spring 默认的命名空间
2.将当前encodedResource添加到currentResources
1.获取 resourceLoader,这边为 XmlWebApplicationContext
加载 bean 定义,由 XmlWebApplicationContext 实现
加载 bean 定义,方法以 do 开头,真正处理的方法
4.registerBeanDefinitions:加载及注册Bean定义
2.使用此上下文的资源加载环境配置 XmlBeanDefinitionReader
2.根据返回的Document注册Bean信息(对配置文件的解析,核心逻辑)
1.获取配置文件路径 String[] configLocations = getConfigLocations();
2.根据配置文件路径加载 bean 定义reader.loadBeanDefinitions(configLocation);
3.加载 bean 定义
0 条评论
回复 删除
下一页