跳至主要內容

SpringBoot自动配置原理

Jin大约 2 分钟

SpringBoot自动配置原理

1、面试官:请说一下SpringBoot自动配置的原理

解答:

1. 在主启动类上添加了SpringBootApplication注解,这个注解组合了EnableAutoConfiguration注解

2. EnableAutoConfiguration注解又组合了Import注解,导入了AutoConfigurationImportSelector类

3. 实现selectImports方法,这个方法经过层层调用,最终会读取META-INF 目录下的 后缀名 为imorts的文件,当然了,boot2.7以前的版本,读取的是spring.factories文件

4. 读取到全类名了之后,会解析注册条件,也就是@Conditional及其衍生注解,把满足注册条件的Bean对象自动注入到IOC容器中

2、自动配置源码分析

遵守约定大于配置的原则,在Boot程序启动后,起步依赖中的一些bean对象会自动注入到IOC容器中

示例:程序引入spring-boot-starter-web 起步依赖,启动后,会自动往ioc容器中注入DispatcherServlet

<!--        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

启动类

@SpringBootApplication
public class BeanRegisterApplication {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(BeanRegisterApplication.class, args);
        System.out.println(context.getBean("dispatcherServlet"));
    }
}

不引入spring-boot-starter-web会报错如下:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'dispatcherServlet' available

引入会打印如下:

org.springframework.web.servlet.DispatcherServlet@6a4ccef7

3、启动类注解@SpringBootApplication分析

源码中多个组合注解

......
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
......
}
  1. 第一个@SpringBootConfiguration

    ......
    @Configuration
    public @interface SpringBootConfiguration {
    ......
    }
    

    存在@Configuration,说明启动类也是一个配置类

  2. @EnableAutoConfiguration 【重要】

    ......
    @AutoConfigurationPackage
    @Import({AutoConfigurationImportSelector.class})
    public @interface EnableAutoConfiguration {
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
        Class<?>[] exclude() default {};
    
        String[] excludeName() default {};
    }
    

    组合注解中的 AutoConfigurationImportSelector

    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
    		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    ......
    	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		if (!isEnabled(annotationMetadata)) {
    			return NO_IMPORTS;
    		}
    		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
    		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    	}
    ......
    }
    
    public interface DeferredImportSelector extends ImportSelector {
    ......
    }
    

    注意观察实现的是DeferredImportSelector,该接口继承的是ImportSelector。上面Bean注册 @import中使用过

    追溯源码发现会读取配置文件META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。里面存放的是配置类的全类名。

    例如:org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration 进入源码:

    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    @AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass(DispatcherServlet.class)
    public class DispatcherServletAutoConfiguration {
        ......
         
        @Configuration(proxyBeanMethods = false)
    	@Conditional(DefaultDispatcherServletCondition.class)
    	@ConditionalOnClass(ServletRegistration.class)
    	@EnableConfigurationProperties(WebMvcProperties.class)
    	protected static class DispatcherServletConfiguration {
            ......
    		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    		public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
    			DispatcherServlet dispatcherServlet = new DispatcherServlet();
    			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
    			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
    			configureThrowExceptionIfNoHandlerFound(webMvcProperties, dispatcherServlet);
    			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
    			dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
    			return dispatcherServlet;
    		}
            ......
        }
        ......
    }
    

    最终读取配置类,解析注册条件,也就是@Conditional及其衍生注解,把满足注册条件的Bean对象自动注入到IOC容器中。

4、自动配置核心

核心是spring.factories 和 .imports 配置文件,也是配置类的全类名存放文件

5、版本支持

版本支持如下:

  1. SpringBoot版本 < SpringBoot2.7x,只支持spring.factories
  2. SpringBoot2.7x <= SpringBoot版本 < SpringBoot3.0 ,支持spring.factories 和 imports
  3. SpringBoot3.0之后, 只支持imports文件
贡献者: Jin