Spring Boot⾃动配置

         根据我们添加的jar包依赖,会⾃动将⼀些配置类的bean注册进ioc容器,我们可以 需要的地⽅使⽤@Autowired或者@Resource等注解来使⽤它。

原理:

  1. 收集spring开发者的编程习惯,整理开发过程使用的常用技术列表(技术集A)
  2. 收集常用技术(技术集A)的使用参数,整理开发过程中每个技术的常用设置列表(设置集B)
  3. 初始化springboot基础环境,加载用户自定义的bean和导入的其他坐标,形成初始化环境
  4. 将技术集A包含的所有技术都定义出来,在spring/springboot启动时默认全部加载
  5. 将技术集A中具有使用条件的技术约定出来,设置成按条件加载,由开发者决定是否使用该技术(与初始化环境比对)
  6. 将设置集B作为配置加载(约定大于配置),减少开发者配置工作量
  7. 开放设置集B的配置覆盖接口,由开发者根据自身需要决定是否覆盖默认配置

        Spring Boot应⽤的启动⼊⼝是@SpringBootApplication注解标注类中的main()⽅法,@SpringBootApplication : SpringBoot 应⽤标注在某个类上说明这个类 是 SpringBoot 的主配置类, SpringBoot 就应该运⾏这个类的 main() ⽅法启 动 SpringBoot 应⽤。

1 @SpringBootApplication

对@SpringBootApplication内部源码进⾏分析

@Target({ElementType.TYPE}) //注解的适⽤范围,Type表示注解可以描述在类、接⼝、注解或枚举中
@Retention(RetentionPolicy.RUNTIME)//表示注解的⽣命周期,Runtime运⾏时
@Documented//表示注解可以记录在javadoc中
@Inherited//表示可以被⼦类继承该注解
@SpringBootConfiguration// 标明该类为配置类
@EnableAutoConfiguration// 启动⾃动配置功
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    // 根据class来排除特定的类,使其不能加⼊spring容器,传⼊参数value类型是class类型。
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};
    // 根据classname 来排除特定的类,使其不能加⼊spring容器,传⼊参数value类型是class的全类名字符串数组。
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};
    // 指定扫描包,参数是包名的字符串数组。
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};
    // 扫描特定的包,参数类似是Class类型数组。
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "nameGenerator"
    )
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

         从上述可以看出,@SpringBootApplication注解是⼀个组合注解,前⾯ 4 个是 注解的元数据信息, 我们主要看后⾯ 3 个注解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个核⼼注解。

2 @SpringBootConfiguration 

        @SpringBootConfiguration : SpringBoot 的配置类,标注在某个类上,表 示这是⼀个 SpringBoot 的配置类。@SpringBootConfiguration注解源码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration// 配置类的作⽤等同于配置⽂件,配置类也是容器中的⼀个对象
@Indexed//加速springboot启动
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

         @SpringBootConfiguration注解内部有⼀个核⼼注解 @Configuration,该注解是Spring框架提供的,表示当前类为⼀个配置类(XML配置 ⽂件的注解表现形式),并可以被组件扫描器扫描。由此可⻅, @SpringBootConfiguration注解的作⽤与@Configuration注解相同,都是标识⼀个可 以被组件扫描器扫描的配置类,只不过@SpringBootConfiguration是被Spring Boot 进⾏了重新封装命名⽽已

3@EnableAutoConfiguration 

        @EnableAutoConfiguration 的源码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage// ⾃动配置包
// Spring的底层注解@Import,给容器中导⼊⼀个组件; 导⼊的组件是AutoConfigurationPackages.Registrar.class
@Import({AutoConfigurationImportSelector.class})
// 告诉SpringBoot开启⾃动配置功能,这样⾃动配置才能⽣效。
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    // 返回不会被导⼊到 Spring 容器中的类
    Class<?>[] exclude() default {};

    // 返回不会被导⼊到 Spring 容器中的类名
    String[] excludeName() default {};
}

         Spring 中有很多以 Enable 开头的注解,其作⽤就是借助 @Import 来收集并注 册特定场景相关的 Bean ,并加载到 IOC 容器。

        @EnableAutoConfiguration就是借助@Import来收集所有符合⾃动配置条件的bean 定义,并加载到IoC容器。

3.1@AutoConfigurationPackage

@AutoConfigurationPackage的源码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
 //设置当前配置所在的包作为扫描包,后续要针对当前的包进行扫描
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

        @AutoConfigurationPackage :⾃动配置包,它也是⼀个组合注解,其中最重 要的注解是 @Import(AutoConfigurationPackages.Registrar.class) ,它 是 Spring 框架的底层注解,它的作⽤就是给容器中导⼊某个组件类,例如 @Import(AutoConfigurationPackages.Registrar.class) ,它就是 将 Registrar 这个组件类导⼊到容器中,可查看 Registrar 类中 registerBeanDefinitions⽅法:

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            // 将注解标注的元信息传⼊,获取到相应的包名
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

         我们对 new PackageImport(metadata).getPackageName() 进⾏检索,看看 其结果 再看register⽅法

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
        // 这⾥参数 packageNames 缺省情况下就是⼀个字符串,是使⽤了注解
        // @SpringBootApplication 的 Spring Boot 应⽤程序⼊⼝类所在的包
        if (registry.containsBeanDefinition(BEAN)) {
            // 如果该bean已经注册,则将要注册包名称添加进去
            AutoConfigurationPackages.BasePackagesBeanDefinition beanDefinition = (AutoConfigurationPackages.BasePackagesBeanDefinition)registry.getBeanDefinition(BEAN);
            beanDefinition.addBasePackages(packageNames);
        } else {
            //如果该bean尚未注册,则注册该bean,参数中提供的包名称会被设置到bean定义中去
            registry.registerBeanDefinition(BEAN, new AutoConfigurationPackages.BasePackagesBeanDefinition(packageNames));
        }

    }

         AutoConfigurationPackages.Registrar这个类就⼲⼀个事,注册⼀个 Bean ,这 个 Bean 就 是 org.springframework.boot.autoconfigure.AutoConfigurationPacka ges.BasePackages , @AutoConfigurationPackage 这个注解的类所在的包 路径,保存⾃动配置类以供之后的使⽤,⽐如给 JPA entity 扫描器⽤来扫描开发 ⼈员通过注解 @Entity 定义的 entity 类。

3.2 @Import(AutoConfigurationImportSelector.class)

        @Import({AutoConfigurationImportSelector.class}) : 将 AutoConfigurationImportSelector 这个类导⼊到 Spring 容器 中, AutoConfigurationImportSelector 可以帮助 Springboot 应⽤将所有 符合条件的 @Configuration 配置都加载到当前 SpringBoot 创建并使⽤的 IOC 容器( ApplicationContext )中。

        可以看到AutoConfigurationImportSelector 重点是实现了 DeferredImportSelector 接⼝Ordered接口和各种Aware 接⼝。

  1. 以Aware结尾的接⼝:以Aware结尾的接⼝提供了对应对象,例如实现BeanFactoryAware接口,就可以获得BeanFactory对象
    public class CartoonCatAndMouse implements ApplicationContextAware {
        private ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }    
    
        public void play(){
            //获取所有bean的名称
            String[] beans = applicationContext.getBeanDefinitionNames();
            for (String bean : beans) {
                System.out.println(bean);
            }
        }
    
    }
    
  2. Ordered接口:当前类在spring容器中的加载顺序
  3. DeferredImportSelector 接⼝:推迟导入选择器

        DeferredImportSelector接⼝继承了ImportSelector接⼝,ImportSelector接⼝又定义了一个新的接口Group,从Group的process方法看,因为是这是一个接口,所以从其实现类AutoConfigurationImportSelector看process方法。 

确定⾃动配置实现逻辑的⼊⼝⽅法: 

        跟⾃动配置逻辑相关的⼊⼝⽅法在 DeferredImportSelectorGrouping DeferredImportSelectorGrouping 类 的 getImports getImports ⽅法处,因此我们就从 DeferredImportSelectorGrouping 类的 getImports ⽅法来开始分析

public Iterable<Entry> getImports() {
// 遍历DeferredImportSelectorHolder对象集合deferredImports,deferredImports集合装了各种ImportSelector,当然这⾥装的是AutoConfigurationImportSelector
            Iterator var1 = this.deferredImports.iterator();

            while(var1.hasNext()) {
                ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
                // 【1】,利⽤AutoConfigurationGroup的process⽅法来处理⾃动配置的相关逻辑,决定导⼊哪些配置类(这个是我们分析的重点,⾃动配置的逻辑全在这了)
                this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
            }
            // 【2】,经过上⾯的处理后,然后再进⾏选择导⼊哪些配置类
            return this.group.selectImports();
        }

        标 【1】 处的的代码是我们分析的重中之重,⾃动配置的相关的绝⼤部分逻辑全在 这⾥了。那 this.group.process(deferredImport.getConfigurationClass().get Metadata(), deferredImport.getImportSelector()) ;主要做的事情就是在this.group 即 AutoConfigurationGroup对象的process⽅法中,传⼊的 AutoConfigurationImportSelector对象来选择⼀些符合条件的⾃动配置 类,过滤掉⼀些不符合条件的⾃动配置类。

注:

        AutoConfigurationGroup:是AutoConfigurationImportSelector的内部类,主 要⽤来处理⾃动配置相关的逻辑,拥有process和selectImports⽅法,然后拥有 entries和autoConfigurationEntries集合属性,这两个集合分别存储被处理后的符 合条件的⾃动配置类;

        AutoConfigurationImportSelector:承担⾃动配置的绝⼤部分逻辑,负责选择⼀些 符合条件的⾃动配置类;

        metadata:标注在SpringBoot启动类上的@SpringBootApplication注解元数据 标【2】的this.group.selectImports的⽅法主要是针对前⾯的process⽅法处理后的 ⾃动配置类再进⼀步有选择的选择导⼊

分析⾃动配置的主要逻辑 

        由上分析,跟⾃动配置逻辑相关的⼊⼝⽅法在AutoConfigurationImportSelector类的process⽅法中 

// 这⾥⽤来处理⾃动配置类,⽐如过滤掉不符合匹配条件的⾃动配置类
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
                return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
            });
    // 【1】,调⽤getAutoConfigurationEntry⽅法得到⾃动配置类放⼊autoConfigurationEntry对象中
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
    // 【2】,⼜将封装了⾃动配置类的autoConfigurationEntry对象装进autoConfigurationEntries集合
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();
    // 【3】,遍历刚获取的⾃动配置类
            while(var4.hasNext()) {
                String importClassName = (String)var4.next();
    // 这⾥符合条件的⾃动配置类作为key,annotationMetadata作为值放进entries集合
                this.entries.putIfAbsent(importClassName, annotationMetadata);
            }

        }

        上⾯代码中我们再来看标 【1】 的⽅法 getAutoConfigurationEntry ,这个⽅ 法主要是⽤来获取⾃动配置类有关,承担了⾃动配置的主要逻辑。

// 获取符合条件的⾃动配置类,避免加载不必要的⾃动配置类从⽽造成内存浪费
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {

        // 获取是否有配置spring.boot.enableautoconfiguration属性,即是否配置@SpringBootApplication注解,默认返回true
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {

 // 获得@Congiguration标注的Configuration类即被审视introspectedClass的注解数据, ⽐如:@SpringBootApplication(exclude =FreeMarkerAutoConfiguration.class),将会获取到exclude = FreeMarkerAutoConfiguration.class和excludeName=""的两个注解数据
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);

// 【1】得到spring.factories⽂件配置的所有⾃动配置类,即原理部分提到的技术集A全部加载
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

// 利⽤LinkedHashSet移除重复的配置类
            configurations = this.removeDuplicates(configurations);

// 得到要排除的⾃动配置类,⽐如注解属性exclude的配置类@SpringBootApplication(exclude =
FreeMarkerAutoConfiguration.class),将会获取到exclude = FreeMarkerAutoConfiguration.class的注解数据
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);

// 检查要被排除的配置类,因为有些不是⾃动配置类,故要抛出异常
            this.checkExcludedClasses(configurations, exclusions);

// 【2】将要排除的配置类移除
            configurations.removeAll(exclusions);

// 【3】因为从spring.factories⽂件获取的⾃动配置类太多,如果有些不必要的⾃动配置类都加载进内存,会造成内存浪费,因此这⾥需要进⾏过滤,注意这⾥会调⽤AutoConfigurationImportFilter的match⽅法来判断是否符合@ConditionalOnBean,@ConditionalOnClass或@ConditionalOnWebApplication,后⾯会重点分析⼀下
            configurations = this.getConfigurationClassFilter().filter(configurations);

// 【4】获取了符合条件的⾃动配置类后,此时触发AutoConfigurationImportEvent事件,⽬的是告诉ConditionEvaluationReport条件评估报告器对象来记录符合条件的⾃动配置类,该事件什么时候会被触发?--> 在刷新容器时调⽤invokeBeanFactoryPostProcessors后置处理器时触发
            this.fireAutoConfigurationImportEvents(configurations, exclusions);

// 【5】将符合条件和要排除的⾃动配置类封装进AutoConfigurationEntry对象,并返回
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

深⼊getCandidateConfigurations⽅法 

        这个⽅法中有⼀个重要⽅法 loadFactoryNames ,这个⽅法是让 SpringFactoryLoader 去加载⼀些组件的名字。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 这个⽅法需要传⼊两个参数getSpringFactoriesLoaderFactoryClass()和getBeanClassLoader()
 // getSpringFactoriesLoaderFactoryClass()这个⽅法返回的是EnableAutoConfiguration.class
 // getBeanClassLoader()这个⽅法返回的是beanClassLoader(类加载器)
        List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
        ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor 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;
    }

继续点开 loadFactory ⽅法

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

//获取出⼊的键
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {

//如果类加载器不为null,则加载类路径下spring.factories⽂件,将其中设置的配置类的全路径信息封装 为Enumeration类对象
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

//循环Enumeration类对象,根据相应的节点信息⽣成Properties对象,通过传⼊的键获取值,在将值切割为⼀个个⼩的字符串转化为Array,⽅法result集合中
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

        从代码中我们可以知道,在这个⽅法中会遍历整个ClassLoader中所有jar包下的 spring.factories⽂件。 spring.factories⾥⾯保存着springboot的默认提供的⾃动配置类 。

        AutoConfigurationEntry⽅法主要做的事情就是获取符合条件的⾃动配置类,避免加载不必要的⾃动配置类从⽽造成内存浪费。

AutoConfigurationEntry⽅法的作用:

  1. 从 spring.factories 配置⽂件中加载 EnableAutoConfiguration ⾃动 配置类);
  2. 若 @EnableAutoConfiguration 等注解标有要 exclude 的⾃动配置类,那 么再将这个⾃动配置类排除掉;
  3. 排除掉要 exclude 的⾃动配置类后,然后再调⽤ filter ⽅法进⾏进⼀步的 过滤,再次排除⼀些不符合条件的⾃动配置类;
  4. 经过重重过滤后,此时再触发 AutoConfigurationImportEvent 事件,告 诉 ConditionEvaluationReport 条件评估报告器对象来记录符合条件的⾃动配 置类;
  5. 最后再将符合条件的⾃动配置类返回。

AutoConfigurationImportSelector 的 filter ⽅法:

List<String> filter(List<String> configurations) {
            long startTime = System.nanoTime();

            // 将从spring.factories中获取的⾃动配置类转出字符串数组
            String[] candidates = StringUtils.toStringArray(configurations);
            boolean skipped = false;
            Iterator var6 = this.filters.iterator();

            int i;
//拿到OnBeanCondition,OnClassCondition和OnWebApplicationCondition
// 然后遍历这三个条件类去过滤从spring.factories加载的⼤量配置类
            while(var6.hasNext()) {
                AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var6.next();

// 判断各种filter来判断每个candidate(这⾥实质要通过candidate(⾃动配置类)拿到其标注的
// @ConditionalOnClass,@ConditionalOnBean和@ConditionalOnWebApplication⾥⾯的注解值)是否匹配,
// 注意candidates数组与match数组⼀⼀对应
                boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);

                // 遍历match数组,注意match顺序跟candidates的⾃动配置类⼀⼀对应
                for(i = 0; i < match.length; ++i) {
                    if (!match[i]) {
                        // 不匹配的将相应的⾃动配置类置空
                        candidates[i] = null;
                        // 标注skipped为true
                        skipped = true;
                    }
                }
            }
        
// 这⾥表示若所有⾃动配置类经过OnBeanCondition,OnClassCondition和OnWebApplicationCondition过滤后,全部都匹配的话,则全部原样返回
            if (!skipped) {
                return configurations;
            } else {
                
                // 建⽴result集合来装匹配的⾃动配置类
                List<String> result = new ArrayList(candidates.length);
                String[] var12 = candidates;
                int var14 = candidates.length;
                for(i = 0; i < var14; ++i) {
                    String candidate = var12[i];
                // 若candidate不为null,则说明是符合条件的⾃动配置类,此时添加到result集合中
                    if (candidate != null) {
                        result.add(candidate);
                    }
                }

                // 打印⽇志
                if (AutoConfigurationImportSelector.logger.isTraceEnabled()) {
                    int numberFiltered = configurations.size() - result.size();
                    AutoConfigurationImportSelector.logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
                }

                // 最后返回符合条件的⾃动配置类
                return result;
            }
        }

        AutoConfigurationImportSelector AutoConfigurationImportSelector 的 filter ⽅法主要做的事情就是 调⽤ AutoConfigurationImportFilter AutoConfigurationImportFilter 接⼝的 match ⽅法来判断每⼀个⾃ 动配置类上的条件注解(若有的 话) @ConditionalOnClass , @ConditionalOnBean 或 @ConditionalOnWebApplication 是否满⾜条件,若满⾜,则返回true,说 明匹配,若不满⾜,则返回false说明不匹配。 

条件注解:

        @Conditional是Spring4新提供的注解,它的作⽤是按照⼀定的条件进⾏判断,满⾜ 条件给容器注册bean。

  • @ConditionalOnBean:仅仅在当前上下⽂中存在某个对象时,才会实例化⼀个 Bean。
  • @ConditionalOnClass:某个class位于类路径上,才会实例化⼀个Bean。
  • @ConditionalOnExpression:当表达式为true的时候,才会实例化⼀个Bean。基 于SpEL表达式的条件判断。
  • @ConditionalOnMissingBean:仅仅在当前上下⽂中不存在某个对象时,才会实例化⼀个Bean。
  • @ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化⼀ 个Bean。
  • @ConditionalOnNotWebApplication:不是web应⽤,才会实例化⼀个Bean。
  • @ConditionalOnWebApplication:当项⽬是⼀个Web项⽬时进⾏实例化。
  • @ConditionalOnNotWebApplication:当项⽬不是⼀个Web项⽬时进⾏实例化。
  • @ConditionalOnProperty:当指定的属性有指定的值时进⾏实例化。
  • @ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
  • @ConditionalOnResource:当类路径下有指定的资源时触发实例化。
  • @ConditionalOnJndi:在JNDI存在的条件下触发实例化。
  • @ConditionalOnSingleCandidate:当指定的Bean在容器中只有⼀个,或者有多 个但是指定了⾸选的Bean时触发实例化。

        selectImports⽅法主要是针对经过排除掉exclude的和被 AutoConfigurationImportFilter接⼝过滤后的满⾜条件的⾃动配置类再进⼀ 步排除exclude的⾃动配置类,然后再排序 。

总结:

  1. 先开发若干种技术的标准实现
  2. springboot启动时加载所有的技术实现对应的配置类
  3. 检测每个配置类的加载条件是否满足,并进行对应的初始化
  4. 切记是先加载所有的外部资源,然后根据初始环境进行条件比对

4.SpringBoot⾃动配置主要做了以下事情:

 1. 从spring.factories配置⽂件中加载⾃动配置类;

2. 加载的⾃动配置类中排除掉 @EnableAutoConfiguration注解的exclude属性指定的⾃动配置类;

3. 然后再⽤AutoConfigurationImportFilter接⼝去过滤⾃动配置类是 否符合其标注注解(若有标注的 话)@ConditionalOnClass , @ConditionalOnBean和 @ConditionalOnWebApplication的条件,若都符合的话则返回匹配结果;

4. 然后触发 AutoConfigurationImportEvent事件,告诉 ConditionEvaluationReport条件评估报告器对象来分别记录符合条件和exclude的⾃动配置类。

5. 最后spring再将最后筛选后的⾃动配置类导⼊IOC容器中

5.4@ComponentScan注解

        主要是从定义的扫描路径中,找出标识了需要装配的类⾃动装配到spring 的bean容 器中。

        常⽤属性如下:

  • basePackages、value:指定扫描路径,如果为空则以@ComponentScan注解的类所在的包为基本的扫描路径
  • basePackageClasses:指定具体扫描的类
  • includeFilters:指定满⾜Filter条件的类
  • excludeFilters:指定排除Filter条件的类 

        includeFilters和excludeFilters 的FilterType可选:ANNOTATION=注解类型 默认、 ASSIGNABLE_TYPE(指定固定类)、ASPECTJ(ASPECTJ类型)、REGEX(正则表达式)、 CUSTOM(⾃定义类型),⾃定义的Filter需要实现TypeFilter接⼝ 

        @ComponentScan的配置如下: 

@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM,
classes = TypeExcludeFilter.class),
 @Filter(type = FilterType.CUSTOM, classes =
AutoConfigurationExcludeFilter.class) })

借助excludeFilters将TypeExcludeFillter及FilterType这两个类进⾏排除

        当前@ComponentScan注解没有标注basePackages及value,所以扫描路径默认为 @ComponentScan注解的类所在的包为基本的扫描路径(也就是标注了 @SpringBootApplication注解的项⽬启动类所在的路径)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot配置指的是在运行时对应用程序的配置进行修改或更新,而不需要重新启应用程序。 在面试中,可能会涉及到Spring Boot配置的原理、作用以及相关的实现方法。 首先,Spring Boot配置的原理是基于Spring框架的属性注入和监听机制。Spring Boot应用程序的配置是通过`application.properties`或`application.yml`文件进行管理的。当应用程序启时,Spring Boot会读取这些配置文件中的属性值并注入到Spring Bean中,从而实现配置的逻辑。 而配置则是通过监听属性值的变化来实现的。Spring Boot提供了`@ConfigurationProperties`注解和`@Value`注解两种常用的配置注入方式。可以通过在配置中使用`@ConfigurationProperties`注解,将需要态修改的属性注入到Bean中。然后,通过添加一个监听器,监听属性值的变化,一旦属性值发生改变,就会触发监听事件并重新加载配置。 有多种方法可以实现Spring Boot配置。一种常用的方法是使用Spring Cloud Config服务来集中管理和存储配置,并通过消息总线发送配置变更的通知。另一种方法是使用Spring Cloud Bus,它使用消息代理将配置的变更通知传播给多个实例。 还可以使用第三方的配置中心,如Apache Zookeeper、Consul等来进行配置。这些配置中心提供了API来更新和获取配置信息,并且支持监听配置变化的功能。 总之,Spring Boot配置是为了方便应用程序的配置管理和更新,使应用程序在运行时可以灵活地适应不同的配置需求。 ### 回答2: Spring Boot配置是指在应用程序运行时可以根据需要态更改配置参数,而无需重启应用程序。这种灵活性使得应用程序能够根据环境的变化或者特定的用户需求进行调整和优化。 在Spring Boot中,我们可以通过使用Spring Cloud Config等工具或者自定义实现来实现配置Spring Cloud Config是Spring Cloud的一个子项目,它提供了一个集中式的配置管理服务,允许将应用程序的配置文件存储在远程仓库中(如Git或SVN),并在运行时态地从这些仓库中获取配置。 使用Spring Cloud Config,我们可以将应用程序的配置信息集中管理,而不需要将配置参数硬编码到代码中。通过轮询或者推送的方式,应用程序可以定时或者实时获取最新的配置信息。这样,我们可以在不重新部署应用程序的情况下,更改配置参数,从而使得应用程序可以快速适应环境的变化或者满足特定的需求。 配置的好处包括: 1. 避免了重新部署应用程序的麻烦和风险,提高了开发和部署效率。 2. 使得应用程序可以根据不同环境的需要进行配置,达到最佳性能和适应性。 3. 实现了配置信息的集中管理,方便追踪和管理配置变更的历史记录。 但是,配置也需要考虑安全性和稳定性的问题。配置信息的修改和获取需要进行权限控制,以防止非法操作。另外,配置可能会对应用程序的稳定性造成一定影响,因此在配置更新过程中需要考虑到应用程序可能的异常处理和兼容性。 总之,Spring Boot配置为应用程序提供了更大的灵活性和可维护性,使得应用程序在运行时可以根据需要态调整参数,从而达到更好的性能和适应性。 ### 回答3: Spring Boot配置是指在程序运行时可以根据需要态更改配置信息的功能。它通过提供一种灵活的配置机制,使得应用程序的配置可以在不重启应用的情况下进行修改和更新。 在Spring Boot中,可以通过使用@ConfigurationProperties注解来定义配置,将配置信息映射到该的属性上。通过@ConfigurationProperties注解,我们可以将外部配置文件中的属性值绑定到配置的属性上。当配置文件中的属性值发生改变时,Spring Boot会自更新配置中对应的属性值。 配置的优点是可以在应用程序运行时实时修改配置信息,而不需要重启应用程序。这样可以提高应用程序的可扩展性和可维护性。例如,在一个具有高流量访问的网站中,如果需要增加线程池的大小来提高并发处理能力,可以通过修改配置文件中的线程池大小属性来达到目的,而不需要停止应用程序。 在Spring Boot中,可以使用Spring Cloud Config来实现配置Spring Cloud Config提供了一种集中化的外部配置管理方案,可以将配置文件存储在Git、SVN或本地文件系统等地方,应用程序可以通过访问配置服务器来获取最新的配置信息。通过Spring Cloud Config,我们可以在运行时修改配置文件,并使得配置信息对应用程序立即生效,实现了配置的功能。 总而言之,Spring Boot配置是指在程序运行时可以实时修改配置信息的功能。它通过使用@ConfigurationProperties注解和Spring Cloud Config等机制来实现,提供了一种灵活且方便的方式来管理和更新应用程序的配置信息。这种能力提高了应用程序的可扩展性和可维护性,使得应用程序能够更加灵活地适应不同的环境和需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值