前言:
spring源码真的很庞大很复杂,要是做到每个方法每个细节都去看都看懂那是大牛干的事,术业有专攻,我只会对我认为重要的细节进行详细剖析。本次会以完全配置类的方式进行解析不使用xml文件,并不是xml的方式不好,我个人完全推崇配置的方式。我会以整体的方式进行详解,里面的代码自己去看对你的帮助更大。
xml与config方式的优点
xml:1:在我们开发中,xml配置文件和代码类是区分开的。不需要绑定到代码中
2:使用xml配置可以让软件更具有扩展性;
3:对象之间的关系一目了然;
4:基于xml配置的时候,只需要修改xml即可,不需要对现有的程序进行修改
5:容易与其他系统进行数据交互。数据共享方便
config:
1:注解的解析可以不依赖于第三方库,可以之间使用Java自带的反射
2:注解和代码在一起的,之间在类上,降低了维护两个地方的成本
3:注解如果有问题,在编译期间,就可以验证正确性,如果出错更容易找
4:使用注解开发能够提高开发效率。不用多个地方维护,不用考虑是否存在“潜规则”
到底使用什么方式根据个人的习惯,或者结合两者的优点进行组合使用也不失为一种方式。
直接进入正题
整个spring代码分析的入口
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);
AnnotationConfigApplicationContext:
这是整个spring的大环境,也可以叫做容器。
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//调用无参构造方法
this();
//注册配置类
register(annotatedClasses);
//刷新容器
refresh();
}
public GenericApplicationContext() {
//创建一个bean工厂
this.beanFactory = new DefaultListableBeanFactory();
}
public AnnotationConfigApplicationContext() {
//调用父类的构造方法
super();
//初始化一个读取器
this.reader = new AnnotatedBeanDefinitionReader(this);
//初始化一个扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
首先调用父类的构造方法对环境中的beanFactory进行了初始化
DefaultListableBeanFactory:
spring环境中的工厂,可以理解为生成bean的原料和机器。
AnnotatedBeanDefinitionReader:
可以理解为一个读取器,把一个加了注解的类转换成beanDefinition。在对reader进行初始化的过程中,往beanDefinitionMap中注册了6个系统内置的beanDefinition。
beanDefinition:很重要!!这个概念是spring的核心
SpringIoc容器管理一个Bean或多个Bean,这些Bean通过我们提供给容器的配置元数据被创建出来(例如,在xml中的定义) 在容器中,这些Bean的定义用BeanDefinition对象来表示,包含以下元数据:
- 全限定类名, 通常是Bean的实际实现类;
- Bean行为配置元素,它们说明Bean在容器中的行为(作用域、生命周期回调等等);
- Bean执行工作所需要的的其他Bean的引用,这些Bean也称为协作者或依赖项;
- 其他配置信息,例如,管理连接池的bean中,限制池的大小或者使用的连接的数量。
Spring官网中对BeanDefinition的解释还是很详细的,但是不是那么通俗易懂,其实BeanDefinition是比较容易解释的:BeanDefinition就是用来描述一个Bean或者BeanDefinition就是Bean的定义。
ClassPathbeanDefinitionScanner:
可以理解为一个扫描器,把一个包路径下的类转换成beanDefinition。这个对象它并不会去做扫描功能,后面的源码可以看到,如果你单独注册了一个类,那么spring会new一个scanner对这个类进行解析转变成beanDefinition,那他做了什么?只有你通过Context中的Scanner的api的方式Scanner.scan("包路径");才会通过这个扫描器进行注册。
还有一个重点!!!在初始化注册器和扫描器的时候都传递了一个this,this是当前的Context环境。也就是说保存了容器的引用。
register(MyConfig.class):注册一个或多个配置类
@ComponentScan("xxxx.xxx")
@Configuration
@Import(MyImportAware.class)
public class MyConfig {
}
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
//调用读取器完成配置类的注册
this.reader.register(annotatedClasses);
}
为什么要在此时手动注册一个配置类
因为spring完成自动扫描的前提是得要知道扫描那些加了注解的类,而这个信息保存在了配置类中的@ComponentScan()注解上,只有这个配置类提前存在与spring容器中才能完成其他类的扫描。
public void register(Class<?>... annotatedClasses) {
//注册的配置类可以是一个集合,循环调用所有的配置类
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
/**
* 通过AnnotatedGenericBeanDefinition()的构造方法把配置类转换成beanDefinition
* 一共有三种把类转换成beanDefinition的方式
* 1.reader
* 2.new beanDefinition(xx.class);
* 3.Scanner
*/
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
/**
* 判断当前配置类上是否加了@Conditional注解
* springboot当中这个注解很重要!!
* @ConditionalOnBean...判断是否要跳过当前配置类
* 就是对该注解进行了扩展!!如果加了该注解直接return不会注册进spring容器中
*/
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//添加InstanceSupplier默认为null,如果这个属性不为null,可以根据这个属性来创建对象
abd.setInstanceSupplier(instanceSupplier);
//拿到当前类上的 @scope 注解上的元信息
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
//给配置类的beanDefintion设置作用域 默认为 Singleton 单例
abd.setScope(scopeMetadata.getScopeName());
//name是通过参数传递进来的默认为null,所以要通过beanNameGenerator生成一个beanName
//默认就是类名的首字母小写
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
/**对配置类上的通用注解进行解析,然后set到beanDefinition中
* 1\. @Lazy 表示延迟初始化
* 2\. @Primary 依赖注入解决多个候选bean
* 3\. @dependsOn 定义Bean初始化及销毁时的顺序
* 4\. @Role 用的少不知道
* 5\. @Description 描述信息
*/
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
//qualifiers是通过参数传递进来的,默认为null
//如果你手动调用了 doRegisterBean(xx.class),这个对象存放的就是你手动给类设置注解
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}else{
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
//definitionCustomizers通过参数传递进来默认为null,判断是否有用户自定义的注解
//如果有就set进beanDefinition中
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
/**
* BeanDefinitionHolder类中封装了beanName、beanDefinition和aliies(别名)
* 为什么要再进行一次封装
* 1.有的类会设置别名
* 2.传递参数的更加方便
*/
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
/**
* 解析ScopedProxyMode属性
* 1.不进行 2.JDK动态代理 3.CGLIB
*/
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//把BeanDefinition添加进beanDefinitionMap
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
//拆分出beanName
String beanName = definitionHolder.getBeanName();
/**
* 先判断beanDefinitionMap中是否已经有了key为beanName的beanDefinition
* 如果存在,继续判断是否允许覆盖,如果不允许保存,允许就覆盖
* 如果不存在,添加进beanFactory中对应的集合
* //this.beanDefinitionMap.put(beanName, beanDefinition);
* //this.beanDefinitionNames.add(beanName);
* //this.manualSingletonNames.remove(beanName);
*/
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//拆分出别名
String[] aliases = definitionHolder.getAliases();
//如果不为null,添加进beanFactory中的aliasMap中,key为别名value为beanDefinition if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
beanDefinitionRegister:
完成了beanDefinition注册进beanDefinitionMap中