一、寻找核心方法
// == 入口
public static void main(String[] args) {
SpringApplication.run(SpringRunner.class, args);
}// == 调用链
org.springframework.boot.SpringApplication#run(java.lang.Class>, java.lang.String...)
org.springframework.boot.SpringApplication#run(java.lang.Class>[], java.lang.String[])
org.springframework.boot.SpringApplication#run(java.lang.String...)
org.springframework.boot.SpringApplication#refreshContext
org.springframework.boot.SpringApplication#refresh
【spring初始化&循环引用】记住
refresh方法
,它非常重要观察它的内部实现:
// ##### IOC容器初始化 #####
// 告知子类要初始化BeanFactory
// BeanDefinition信息的读取是在子类的refreshBeanFactory()方法里完成的
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 准备bean工厂以在此上下文中使用。
this.prepareBeanFactory(beanFactory);
// ##### 著名的九大方法 #####
try {
// 设置beanFactory的后置处理
postProcessBeanFactory(beanFactory);
// 调用beanFactory的后置处理,如springboot自动装配获取配置的Entity
invokeBeanFactoryPostProcessors(beanFactory);
// 注册beanFactory的后置处理
registerBeanPostProcessors(beanFactory);
// 初始化上下文的消息
initMessageSource();
// 初始化上下的事件
initApplicationEventMulticaster();
// 初始化一些特殊的bean
onRefresh();
// 检查一些监听的bean并注册到容器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons,spring bean对象初始化在这里
finishBeanFactoryInitialization(beanFactory);
// 发布容器事件,结束Refresh过程
finishRefresh();
二、注册和扫描 本节深入分析构建BeanFactory的过程。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// == 调用链
org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
// -- 分析注解方式注入
org.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions
1.向容器注册对象信息 注入的本质就是向容器(也有叫上下文的,就是Context的直译)——实质就是一个Map注册类的描述信息。
用代码描述就是:
beanDefinitionMap.put(BeanDefinition)
看看具体实现:
// == 注册逻辑
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
if (!this.annotatedClasses.isEmpty()) {
reader.register(this.annotatedClasses.toArray(new Class>[this.annotatedClasses.size()]));
}
}// == 调用链
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean(java.lang.Class>)
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean
这个方法值得细说一下:
void doRegisterBean(Class annotatedClass, @Nullable Supplier instanceSupplier, @Nullable String name,
@Nullable Class extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {//## 被注解修饰的对象,会被封装成BeanDefinition结构
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//为注解Bean定义生成Bean名称
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// BeanDefinition再次封装
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// ## 注入
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}// == 调用链
org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition
// -- 前面创建的工厂是DefaultListableBeanFactory
org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
最终的注入逻辑:
// 存储注册信息的BeanDefinition
private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// ## 注入的本质
this.beanDefinitionMap.put(beanName, beanDefinition);
}
2.扫描指定package的配置信息 无它,只为扩大扫描范围。
默认只注入SpringRunner(Starter类)的子包
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
//为容器设置类路径Bean定义扫描器
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
if (!this.basePackages.isEmpty()) {
scanner.scan(this.basePackages.toArray(new String[this.basePackages.size()]));
}
}// == 调用链
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScanprotected Set doScan(String... basePackages) {
//遍历扫描所有给定的包
for (String basePackage : basePackages) {
// ## 同样执行注入流程
registerBeanDefinition(definitionHolder, this.registry);
}
}
未完待续(懒癌发作……)
推荐阅读
- Java毕业设计项目实战篇|Java项目:(小程序)物业管理系统(spring+spring mvc+mybatis+layui+微信小程)
- =======j2ee|spring用注解实现注入的@resource,@autowired,@inject区别
- jar|springboot项目打成jar包和war包,并部署(快速打包部署)
- 数据库|效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】)...
- java人生|35K 入职华为Java开发那天,我哭了(这 5 个月做的一切都值了)
- Java毕业设计项目实战篇|Java项目:在线嘿嘿网盘系统设计和实现(java+Springboot+ssm+mysql+maven)
- 微服务|微服务系列:服务发现与注册-----Eureka(面试突击!你想了解的Eureka都在这里.持续更新中......)
- java|ApplicationListener和SpringApplicationRunListener的联系
- Spring|SpringSecurity--自定义登录页面、注销登录配置