Spring Boot自动配置原理

Spring Boot自动配置原理

前言

为什么说Spring Boot使用了"习惯优于配置"(约定优于配置)的理念?难道Spring Boot真的不需要配置吗?

其实Spring Boot使用自动配置,它将这些配置当做一种约定或习惯,让开发人员很容易创建一个独立运行、准生产级别的基于Spring框架的项目。

那么这种自动配置是怎么实现的呢?

一、 入口类

Spring Boot通常都有一个名为*Application的入口类,而入口类中有一个入口方法(main方法),在main方法中使用SpringApplication.run(*Application.class, args),启动Spring Boot项目。

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

二、 核心注解:@SpringBootApplication

@SpringBootApplication是Spring Boot的核心注解,也是一个组合注解(主要组合了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan)。源码如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    //需要排除的自动配置类
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};

    //需要排除的自动配置类类名
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    //扫描包路径
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    //扫描包路径类
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}

其中:

  • @SpringBootConfiguration:Spring Boot的配置类,标注在某个类上,表示这是一个Spring Boot的配置类。
  • @ComponentScan:包扫描
  • @EnableAutoConfiguration:让Spring Boot根据类路径中的jar包依赖为当前项目进行自动配置(核心功能)。

三、注解:@EnableAutoConfiguration

@SpringBootApplication注解是一个组合注解,而@EnableAutoConfiguration注解为它提供了核心功能。其源码如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    //自动配置的总开关名
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
	//需要排除的自动配置类
    Class<?>[] exclude() default {};
	//需要排除的自动配置类类名
    String[] excludeName() default {};
}

从@EnableAutoConfiguration注解的源码可以看出,其功能主要是由@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})提供

1. 注解:@AutoConfigurationPackage

该注解的作用就是将主配置类(即@SpringBootApplication 标注的类)所在的包及其子包里的所有类都纳入 Spring 容器。开启此注解,Spring Boot会自动扫描@SpringBootApplication所在类的同级包以及下级包中的Bean。故一般建议入口类放置在groupId+arctifactId组合的包名下。

注解@AutoConfigurationPackage源码:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

从源码中可以看出Import(导入)了Registrar,其源码如下:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
        }
    }

以上的调用register方法其实是注册了一个Bean的定义,new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()返回了当前主程序类的同级以及子级的包组件。

2. 类:AutoConfigurationImportSelector

@Import({AutoConfigurationImportSelector.class}),导入自动配置的组件,@Import导入了选择器AutoConfigurationImportSelector。

查看AutoConfigurationImportSelector源码,其中通过spring工厂类加载工厂配置的方法源码如下

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

从上面源码中可以看到这个方法调用了SpringFactoriesLoader.loadFactoryNames方法

SpringFactoriesLoader源码如下

public final class SpringFactoriesLoader {
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();

    private SpringFactoriesLoader() {
    }
 	......
}

综上可知,AutoConfigurationImportSelector使用SpringFactoriesLoader.loadFactoryNames方法来扫描具有META-INF/spring.factories文件的jar包,而spring-boot-autoconfigure-2.1.0.RELEASE.jar中就有一个spring.factories文件,此文件声明的自动配置如下:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
......

这就是Spring Boot自动配置的设计,从配置文件加载常用的默认配置。

四、 实战

Spring Boot 自定义自动配置(自定义starter pom)

五、关闭特定的自动配置

使用@SpringBootApplication注解的exclude参数,例:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

六、参考书籍

《JavaEE开发的颠覆者 Spring Boot实战》

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zarathusa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值