springboot2.7及springboot3中自动配置的变化

大家在面试中问到springboot如何实现的自动配置
诶,不要傻背错八股了,以往 入口类上的@SpringBootApplication注解引入@EnableAutoConfiguration,再 @Import({AutoConfigurationImportSelector.class}) ,其中代码实现根据META-INF/spring.factories文件读取需要自动配置的类了

从springboot 2.7之后的版本中,改为了META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,老的方式还能兼容,而 Springboot3之后完全放弃之前的方式,因此升级springboot版本后,引入的任何三方依赖,如nacos,dubbo,mybatis-plus等等依赖则需要升级相应的版本,否则无法实现自动配置并报错
如图如示

@SpringBootApplication

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration  
@EnableAutoConfiguration   //引入EnableAutoConfiguration   
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface 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 {};
}

查看AutoConfigurationImportSelector 的getAutoConfigurationEntry方法

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
    private static final String[] NO_IMPORTS = new String[0];
    private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
    private ConfigurableListableBeanFactory beanFactory;
    private Environment environment;
    private ClassLoader beanClassLoader;
    private ResourceLoader resourceLoader;
    private ConfigurationClassFilter configurationClassFilter;

    public AutoConfigurationImportSelector() {
    }

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

   ...省略

    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); //这行查找配置候选列表
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationEntry(configurations, exclusions);
        }
    }
       ...省略
       
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).getCandidates();  //这里是实现,注意这里第一个参数是AutoConfiguration类信息
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

可以发现ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).getCandidates()是最终实现,进去看源码

public final class ImportCandidates implements Iterable<String> {
    private static final String LOCATION = "META-INF/spring/%s.imports";
    private static final String COMMENT_START = "#";
    private final List<String> candidates;

...省略

//classLoader转入的是org.springframework.boot.autoconfigure.AutoConfiguration 
    public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
        Assert.notNull(annotation, "'annotation' must not be null");
        ClassLoader classLoaderToUse = decideClassloader(classLoader);
        String location = String.format("META-INF/spring/%s.imports", annotation.getName()); //明显看到,查找地址已经发生了变化 ,最终拼接为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
        Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
        List<String> importCandidates = new ArrayList();

        while(urls.hasMoreElements()) {
            URL url = (URL)urls.nextElement();
            importCandidates.addAll(readCandidateConfigurations(url));
        }

        return new ImportCandidates(importCandidates);
    }

从以上源码可以发现,在springboot3之后,已完全放弃是读META-INF/spring.factories的读取。而是从传的AutoConfiguration.class取的类名称。即org.springframework.boot.autoconfigure.AutoConfiguration。拼接之后 ,META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。

nacos的自动配置为例在这里插入图片描述

需要软件开发,小程序,网站建设可以私信或搜索向上突破工作室 www.yesup.top

99元阿里云服务器
通义灵码-协助编码解答
99元腾讯云服务器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值