SpringBoot源码学习(三)
我们说在springApplication类中中的prepareContext方法中将我们的启动类注册到了spring容器中。当时分析的在loader.load()方法中.那么这个方法又是怎么做的。根据正常的想法我们知道如果拿到了启动类那么就拿到了启动类上边的注解,而启动类上边的注解就包含了太多的信息。通过这些信息就可以将项目所需要的类全部注册到BeanDefinitionLoader中,但是前提是我们要多这个类有所了解。才能逐步去跟进我们的猜想。
打开源码之后,发现这个类提供的方法不多,但是相关的类比较多。
那么咋看看这些类大概都是做什么的
private final Object[] sources;
//解析注解的bean
private final AnnotatedBeanDefinitionReader annotatedReader;
//注册xml中的bean
private final XmlBeanDefinitionReader xmlReader;
private BeanDefinitionReader groovyReader;
//传入的是包路径
private final ClassPathBeanDefinitionScanner scanner;
private ResourceLoader resourceLoader;
大概得想法就是这样,那么程序中是怎么做的?我们详细看一些其提供的各种load方法、
//根据类型判断采用那种方式进行load
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class) {
//传入的是类
return this.load((Class)source);
} else if (source instanceof Resource) {
return this.load((Resource)source);
} else if (source instanceof Package) {
return this.load((Package)source);
} else if (source instanceof CharSequence) {
return this.load((CharSequence)source);
} else {
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
}
//如果传入的是类,那么就用 annotatedReader注册
private int load(Class<?> source) {
if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
this.load(loader);
}
if (this.isComponent(source)) {
this.annotatedReader.register(new Class[]{source});
return 1;
} else {
return 0;
}
}
其他方法类似。这里不在赘述。我们继续跟踪我们的load方法。
通过查看annotationConfigServletWebServerApplicationContext类的继承关系图,我们发现其本质上有BeanDefinitionLoader身影。
而在GenericApplicationContext我们又发现了BeanFactory,因此也就是说
annotationConfigServletWebServerApplicationContext已经包含了一切。
了解了这些,我们从prepareContext中开始寻找load的真谛。
我们看到在prepareContext中BeanDefinitionLoader,其中的rources就是我们的启动了,registry就是我们的annotationConfigServletWebServerApplicationContext。但是我们在springApplication中就已经通过createApplicationContent创建了BeanDefinitionLoader,这里为啥要重新创建?
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
return new BeanDefinitionLoader(registry, sources);
}
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
看样子是要做一下处理了。我们看到这里的loader其实是new出来的,并不是从content中拿取的,因为我们最终还是要将bean注册到content中的beanfactory中,因此看的出来,这里采用new的方式更像是被看做工具。因为并不会影响content中注册的bean的最终目的。
我们进去laod方法
public int load() {
int count = 0;
//这里的resource就是我们上边createBeanDefinitionLoader方法传入的
//启动类
Object[] var2 = this.sources;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Object source = var2[var4];
count += this.load(source);
}
return count;
}
我们看看这里的this.load(source);正好就是咋那会儿看的根据不同类型的传入参数进行不同的load方法。
显然我们传入的是class。那么我们就进入第一个方法。
这块采用的注解的reader进行注册。
为了更好的理解这个reader,我们有必要看一下他的初始化方法。看到最后发现了很长的一段代码。我们就传入了content,没想到居然有那么复杂的逻辑。那么这块到底是干啥的?看着这么多的代码有没有感到恐惧。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
//从content中获取beanfactory
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
//设置依赖比较器,解析@Order和@Priority
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
//设置bean的@Autowired解析器
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
//如果我们的content中没有包含 ConfigurationClassPostProcessor那就注册到content中
//这里的ConfigurationClassPostProcessor是一个后置处理器
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//如果没有AutowiredAnnotationBeanPostProcessor处理器,那就注册进去
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//注册CommonAnnotationBeanPostProcessor
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//EventListenerMethodProcessor的注册
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
通过上述的代码详解,我们发现初始化AnnotatedBeanDefinitionReader的时候居然做了那么多工作。但是这里有一个特别重要的概念:后置处理器。
我们看看它怎么工作的
我们来手动实现一个,然后看看有什么蛛丝马迹
@Component
public class MyAppTest implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
System.out.println("注册bean");
//这里的BeanDefinitionRegistry应该就是content
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
//这里就是bean工厂
System.out.println("这里是工厂");
}
}
启动测试项目
发现实现了该接口的方法的类,会在bean容器加载结束,bean实例化之前进行调用。那么如果定义多个这样的类是不是会每个都执行一下?咋继续测试一下。发现还真实这么一回事。那么就好理解上边哪些后置处理器了。因为我们可以看到在这个接口的入参都是重量级元素,那可是可以轻松的获取所有bean的呀,所以相当于说可以对其进行各种操作。上边注册的哪些后置处理器其实就是用来解析的。解析结束之后就可以实例化了。是不是发现这个接口非常好?我目前是这样想的。但是至于在哪里去掉这个接口,我想应该在我们之前分析的那个核心方法中。就是refresh中。这个后期咋再突破。
看的出来,这个loader.load()目前来说就只把启动类注册到了content中了。那么其他的类是在那块逻辑中会被注册进来?我想是在那些后置处理器中。
- BZOJ 1088: [SCOI2005]扫雷Mine【思维题,神奇的模拟+枚举】
- 浅谈关于特征选择算法与Relief的实现
- HDU 5752 Sqrt Bo【枚举,大水题】
- 移动测试 Appium源码初探
- UESTC 1599 wtmsb【优先队列+排序】
- BZOJ 1029: [JSOI2007]建筑抢修【优先队列+贪心策略】
- UVA 1030 - Image Is Everything【模拟+思维+迭代更新】
- C/C++中对链表操作的理解&&实例分析
- COGS 2482. Franky的胡子【二分,高精度】
- 【AlphaGo Zero 核心技术-深度强化学习教程代码实战02】理解gym的建模思想
- Kruscal(最小生成树)算法模版
- BZOJ 3680: 吊打XXX【模拟退火算法裸题学习,爬山算法学习】
- 区块链概况:什么是比特币
- 简化版桶排序操作模版
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- [记录点滴] OpenResty中Redis操作总结
- [源码解析] 从TimeoutException看Flink的心跳机制
- [记录点滴] 一个解决Lua 随机数生成问题的办法
- [记录点滴] 记录一次用 IntelliJ IDEA遇到scope provided 的坑
- [记录点滴] 一个Python中实现flatten的方法
- [源码解析]Oozie来龙去脉之提交任务
- [记录点滴]Ionic编译过程的研究
- [记录点滴]OpenResty 支持http v2的问题
- [源码解析]Oozie来龙去脉之内部执行
- [记录点滴]编译安装luarocks、luacheck、luautf8
- [笔记整理] 一维搜索
- [记录点滴] 使用工具和命令对redis数据进行备份恢复
- [记录点滴]Spring Boot Admin源码分析笔记
- [记录点滴] luaxml编译过程
- [源码解析] Flink UDAF 背后做了什么