Spring源码系列整体栏目
内容 | 链接地址 |
---|---|
【一】spring源码整体概述 | https://blog.csdn.net/zhenghuishengq/article/details/130940885 |
【二】通过refresh方法剖析IOC的整体流程 | https://blog.csdn.net/zhenghuishengq/article/details/131003428 |
【三】xml配置文件启动spring时refresh的前置工作 | https://blog.csdn.net/zhenghuishengq/article/details/131066637 |
【四】注解方式启动spring时refresh的前置工作 | https://blog.csdn.net/zhenghuishengq/article/details/131113249 |
【五】refresh中prepareRefresh的执行流程 | https://blog.csdn.net/zhenghuishengq/article/details/131186016 |
【六】refresh中obtainFreshBeanFactory的执行流程 | https://blog.csdn.net/zhenghuishengq/article/details/131286888 |
一,bean工厂的创建
前一篇了解了refresh的第一个方法prepareRefresh ,主要是初始化环境,实例化一些监听器和环境等。接下来讲解refresh中的第二个方法,obtainFreshBeanFactory()。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//1:准备刷新上下文环境
prepareRefresh();
//2:获取告诉子类初始化Bean工厂,不同工厂有不同的实现
// 并且将配置文件的属性值加载到当前工厂中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//3:对bean工厂进行填充属性
prepareBeanFactory(beanFactory);
try {
// 第四:留个子类去实现该接口,bean工厂的后置处理器
postProcessBeanFactory(beanFactory);
// 调用我们的bean工厂的后置处理器.
//1. 会在此将class扫描成beanDefinition 2.bean工厂的后置处理器调用
invokeBeanFactoryPostProcessors(beanFactory);
// 注册我们bean的后置处理器
registerBeanPostProcessors(beanFactory);
// 初始化国际化资源处理器.
initMessageSource();
// 创建事件多播器
initApplicationEventMulticaster();
// 这个方法同样也是留个子类实现的springboot也是从这个方法进行启动tomcat的.
onRefresh();
//把我们的事件监听器注册到多播器上
registerListeners();
// 实例化我们剩余的单实例bean.
finishBeanFactoryInitialization(beanFactory);
// 最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
finishRefresh();
}
}
}
在refresh的前置工作中,已经提前初始化了一个默认工厂DefaultListableBeanFactory,而这一步,就是初始化具体的工厂实现。接下来继续往下面的源码看 ,此时会调用一个 obtainFreshBeanFactory() 方法
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
进去这个方法中可以发现,第一步就是会进行一个刷新bean工厂的方法 refreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
/**
* xml加载spring会在这里加载beanDefinition
* javaconfig只是刷新了beanFactory
*/
refreshBeanFactory();
//返回我们的bean工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
1,refreshBeanFactory()
1,接下来查看这个刷新bean工厂的方法,首先会判断bean工厂是否存在,存在则销毁原先的bean工厂,然后再创建一个默认的工厂 DefaultListableBeanFactory ,创建工厂的过程主要是加载配置文件,设置属性等。
@Override
protected final void refreshBeanFactory() throws BeansException {
//若已经存在了 就信息销毁等操作
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//为我们的Spring应用上下文对象创建我们的beanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//为容器设置一个序列化ID,可以通过反序列化获取bean工厂
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//加载我们的bean定义
loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
...
}
}
2,这个创建的bean工厂就是我们熟悉的默认bean工厂 DefaultListableBeanFactory
//为我们的spring 上下文创建我们的内置的beanFactory
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
3,随后就是设置一个序列化的id,可以通过反序列的形式获取到对应的beanFactory
beanFactory.setSerializationId(getId());
4,随后就是定制化bean工厂的操作,会设置两个重要的属性,就是允许覆盖bean定义和允许循环依赖,可以重写这两个方法,修改这两个值的默认属性。
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
5,再接着就是以加载bean定义的形式将bean工厂加载,其具体的方法实现是 loadBeanDefinitions
loadBeanDefinitions(beanFactory);
在这个加载bean定义的抽象类中,可以看到存在四种不同的实现,分别就是对应着不同方式获取上下文的方式
以注解的方式,继续往下看,可以发现在内部存在着大量的方法的重载,而此时bean定义的信息时存储在工厂类里面的
在前面两步里面,主要是创建一个读取器和扫描器,获取一些系统环境和变量,资源解析器,处理一些条件注解,加载一些bean的后置处理器等
//读取器
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
//扫描器
ClassPathBeanDefinitionScanner scan = getClassPathBeanDefinitionScanner(beanFactory);
随后再获取bean容器的构造器,如果不存在则重新注册一个单例的构造器
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
随后再获取一个数据解析器 ScopeMetadataResolver
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
1.1,reader.register
在加载完这些配置之后,接下来就是真正的去对这些bean定义进行注册
reader.register(ClassUtils.toClassArray(this.annotatedClasses));
真正的注册bean的方法是这个 doRegisterBean 方法
该方法中会存储一些@Configuration注解的类
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
也会对一些条件进行筛选判断,如@ConditionalOnClass,@ConditionalOnType等,以及解析一些bean的作用域,填充一些bean的属性,如懒加载等等,最后将这个bean定义进行注册,具体的注册逻辑在上一篇详细的写过
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry)
1.2,scanner.scan
在reader注册完之后,接下来对一些xml文件或者一些包进行扫描的工作
scanner.scan(StringUtils.toStringArray(this.basePackages));
其具体的扫描扫描方法如下,真正扫描配置类的工作是这个 doScan 方法
public int scan(String... basePackages) {
//还没有扫描mapper包之前 容器中所有的bean定义个数
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//真正的扫描我们的mapper包的mapper类
//此处调用的是子类的doScan因为被重写了
doScan(basePackages);
// 注册系统中的配置类处理器
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//返回扫描出mapper的bean定义的个数
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
接下来查看这个doscan方法 , 如下图所示
首先会创建一个 BeanDefinitionHolder 对象用于保存bean定义,这个对象里面存储着bean定义,属性等
//创建bean定义的holder对象用于保存扫描后生成的bean定义对象
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
随后一步就是循环这个作为参数传进来的包路径,第一步就是找到候选的 Components
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
在上面reader.register注册中,在doRegisterBean 方法中将 @Configuration 注解先注册成beanDifinition,所以@Configuration比@Component注解先加载成bean定义。接下来继续查看这个 findCandidateComponents 方法,会对包路径进行解析
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
//验证是否为空
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
在使用注解获取上下文启动spring时,在refresh的前置工作中,就会注册一个 includeFilters 和 excludeFilters ,默认会将所有的带有 @Component,@Controller,@Service 等等注解的类加载到这个 includeFilters 的过滤器中,也可以手动将他加入到 excludeFilters 中,这样spring容器就不会加载
protected void registerDefaultFilters() {
//加入扫描我们的@Component的
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
....
}
接着上文,如果是包含在这个包含过滤器中,则直接将这个容器加入到包中,否者会继续扫描这些候选者们,会判断这些文件是否可读等。
看完doScan方法找到全部的候选beanDefinition之后,这些bean定义就是符合标准可以注册到bean工厂的一些bean定义,接下来就会对这些bean定义设置一些属性,随后就是关键的一步,就是将我们解析出来的组件bean定义注册到我们的IOC容器中,随后将这个bean定义返回
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
最后又会调用具体的 doRegisterBean 方法用于真正的注册bean定义
<T> void doRegisterBean(...){}
总结来说,不管是使用读取器注册还是使用扫描器进行扫描操作,都是为了生成bean定义,并将这个bean定义加入到BeanDifinitionMap中,随后交给bean工厂去生产。
2,getBeanFactory
在刷新完bean工厂之后,随后就是get获取一个bean工厂文章来源:https://www.toymoban.com/news/detail-496337.html
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
获取bean工厂的方法如下,加了一个同步锁,随后将这个bean工厂对象返回文章来源地址https://www.toymoban.com/news/detail-496337.html
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
synchronized(this.beanFactoryMonitor) {
if (this.beanFactory == null) {
throw new IllegalStateException("...");
}
return this.beanFactory;
}
}
到了这里,关于【spring源码系列-06】refresh中obtainFreshBeanFactory方法的执行流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!