SpringBoot自动配置底层原理

首先是启动类

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

发现只有一个注解,一个run函数

先看@SpringBootApplication注解:

@Target(ElementType.TYPE) // 注解的适用范围,其中TYPE用于描述类、接口(包括包注解类型)或enum声明
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期,保留到class文件中(三个生命周期)
@Documented // 表明这个注解应该被javadoc记录
@Inherited // 子类可以继承该注解
@SpringBootConfiguration // 继承了Configuration,表示当前是注解类
@EnableAutoConfiguration // 开启springboot的注解功能,springboot的四大神器之一,其借助@import的帮助
@ComponentScan(excludeFilters = { // 扫描路径设置(具体使用待确认)
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
} 

再看这个注解里有啥:

  • @SpringBootConfiguration // 继承了Configuration,表示当前是注解
  • @EnableAutoConfiguration // 开启springboot的注解功能,springboot的四大神器之一,其借助@import的帮助
  • @ComponentScan(excludeFilters = { // 扫描路径设置(具体使用待确认)

1.@Configuration配置类注解

这就是标注是配置类,就配置文件,比如mq的队列交换机的配置,@SpringBootConfiguration 继承了Configuration,表示当前是注解类

@Configuration
public class MockConfiguration{
    @Bean
    public MockService mockService(){
        return new MockServiceImpl();
    }
}

2.@ComponentScan 扫描bean

  • 对应xml配置中的元素;
  • 重点:ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义;
  • 将这些bean定义加载到IoC容器中管理
  • 我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。

注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages
例如:

@ComponentScan({"com.mbyte.easy.verificationCode"
,"com.mbyte.easy.emailProducer.listener"
,"com.mbyte.easy.RabbitMQConfig"})

3.@EnableAutoConfiguration 最重要的自动配置

在spring框架中就提供了各种以@Enable开头的注解,例如: @EnableScheduling、@EnableCaching、@EnableMBeanExport等; @EnableAutoConfiguration的理念和做事方式其实一脉相承简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义。  
举例:

  • @EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器【定时任务、时间调度任务】
  • @EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器【监控JVM运行时状态】
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage【重点注解】
@Import(AutoConfigurationImportSelector.class)【重点注解】
public @interface EnableAutoConfiguration {
...
}

其中最重要的两个注解已经标注:1、@AutoConfigurationPackage 2、@Import(AutoConfigurationImportSelector.class)

当然还有其中比较重要的一个类就是:EnableAutoConfigurationImportSelector.class

1、@AutoConfigurationPackage**

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
 
}

@Import(AutoConfigurationPackages.Registrar.class)

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
 
        @Override
        public void registerBeanDefinitions(AnnotationMetadata metadata,
                BeanDefinitionRegistry registry) {
            register(registry, new PackageImport(metadata).getPackageName());
        }
 
        ……
 
    }

它其实是注册了一个Bean的定义;
new PackageImport(metadata).getPackageName(),它其实返回了当前主程序类的同级以及子级的包组件(重点);这也就是为什么,我们要把DemoApplication放在项目的最高级中。这就是约定大于配置

2. @Import({AutoConfigurationImportSelector.class})

EnableAutoConfigurationImportSelector:导入哪些组件的选择器;
将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;
会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件;有很多配置了@AutoConfiguration才会被自动导入

Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;以前我们需要自己配置的东西,自动配置类都帮我们;自动配置器会跟根据传入的factoryClass.getName()到项目系统路径下所有的spring.factories文件中找到相应的key,从而加载里面的类。

自动配置幕后英雄:SpringFactoriesLoader详解

借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!

SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置,加载工厂类。

就是解耦了,不再是源代码写死的了,而是从classpath中搜寻所有的META-INF /spring.factories配置文件,并将其中org.springframework.boot.autoconfigure. EnableAutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

你可能感兴趣的:(spring,spring,boot)