springboot-spring源码系列(四)

241 阅读6分钟

前言:

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中

下一篇将会来到springIOC最核心最重要的方式    refresh()!!!!