Skip to content

SpringBoot

Q&A

SpringBoot自动装配原理

Spring Boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar

SpringBoot 的核心注解 SpringBootApplication

java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
<1.>@SpringBootConfiguration
<2.>@ComponentScan
<3.>@EnableAutoConfiguration
public @interface SpringBootApplication {

}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration //实际上它也是一个配置类
public @interface SpringBootConfiguration {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
<1.>@SpringBootConfiguration
<2.>@ComponentScan
<3.>@EnableAutoConfiguration
public @interface SpringBootApplication {

}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration //实际上它也是一个配置类
public @interface SpringBootConfiguration {
}

可以把 @SpringBootApplication看作是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:

  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
  • @Configuration:允许在上下文中注册额外的 bean 或导入其他配置类
  • @ComponentScan: 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilterAutoConfigurationExcludeFilter

image-20230112164305474

@EnableAutoConfiguration 是实现自动装配的重要注解,我们以这个注解入手。

java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

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

    String[] excludeName() default {};
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

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

    String[] excludeName() default {};
}

这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories 的jar包。

java
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

}

public interface DeferredImportSelector extends ImportSelector {

}

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
}
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

}

public interface DeferredImportSelector extends ImportSelector {

}

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
}
java
private static final String[] NO_IMPORTS = new String[0];

//获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    // <1>.判断自动装配开关是否打开
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        //<2>.获取所有需要装配的bean
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}
private static final String[] NO_IMPORTS = new String[0];

//获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    // <1>.判断自动装配开关是否打开
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        //<2>.获取所有需要装配的bean
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}

getAutoConfigurationEntry()方法,这个方法主要负责加载自动配置类的

image-20230112164654112

java
private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
    //<1>.
    if (!this.isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    } else {
        //<2>.
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        //<3>.
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        //<4>.
        configurations = this.removeDuplicates(configurations);
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        this.checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = this.filter(configurations, autoConfigurationMetadata);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}
private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
    //<1>.
    if (!this.isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    } else {
        //<2>.
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        //<3>.
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        //<4>.
        configurations = this.removeDuplicates(configurations);
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        this.checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = this.filter(configurations, autoConfigurationMetadata);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}

第 1 步:

判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.propertiesapplication.yml 中设置

image-20230112164923407

第 2 步

用于获取EnableAutoConfiguration注解中的 excludeexcludeName

第 3 步

获取需要自动装配的所有配置类,读取META-INF/spring.factories

spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

image-20230112165023728

第 4 步

筛选,@ConditionalOnXXX 中的所有条件都满足,该类才会生效。

java
//举例: RabbitAutoConfiguration
@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}
//举例: RabbitAutoConfiguration
@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}

image-20230112165110441

spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔;

SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

Spring Boot启动流程

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

从源码声明可以看出,@SpringBootApplication相当于 @SpringBootConfiguration + @ComponentScan + @EnableAutoConfiguration ,因此我们直接拆开来分析。

上面三个注解都在做一件事:注册bean到spring容器。他们通过不同的条件不同的方式来完成:

  • @SpringBootConfiguration 通过与 @Bean 结合完成Bean的 JavaConfig 配置;
  • @ComponentScan 通过范围扫描的方式,扫描特定注解注释的类,将其注册到Spring容器;
  • @EnableAutoConfiguration 通过 spring.factories 的配置,并结合 @Condition 条件,完成bean的注册;

除了上面的三个注解,还可以使用@Import注解将bean注册到Spring容器

  • @Import 通过导入的方式,将指定的class注册解析到Spring容器;

启动流程

SpringApplication的实例化

  • 推断应用类型是否是Web环境
  • 设置初始化器(Initializer)
  • 设置监听器(Listener)
  • 推断应用入口类(Main)

SpringApplication.run方法

  • 获取SpringApplicationRunListeners
  • 准备配置环境ConfigurableEnvironment
  • 创建ApplicationContext应用上下文
  • ApplicationContext前置处理
  • ApplicationContext刷新
  • ApplicationContext后置处理

构造方法解析

java
// SpringApplication.java

/**
 * 资源加载器
 */
private ResourceLoader resourceLoader;
/**
 * 主要的 Java Config 类的数组
 */
private Set<Class<?>> primarySources;
/**
 * Web 应用类型
 */
private WebApplicationType webApplicationType;

/**
 * ApplicationContextInitializer 数组
 */
private List<ApplicationContextInitializer<?>> initializers;
/**
 * ApplicationListener 数组
 */
private List<ApplicationListener<?>> listeners;

public SpringApplication(Class<?>... primarySources) {
    this(null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 初始化 initializers 属性
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 初始化 listeners 属性
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}
// SpringApplication.java

/**
 * 资源加载器
 */
private ResourceLoader resourceLoader;
/**
 * 主要的 Java Config 类的数组
 */
private Set<Class<?>> primarySources;
/**
 * Web 应用类型
 */
private WebApplicationType webApplicationType;

/**
 * ApplicationContextInitializer 数组
 */
private List<ApplicationContextInitializer<?>> initializers;
/**
 * ApplicationListener 数组
 */
private List<ApplicationListener<?>> listeners;

public SpringApplication(Class<?>... primarySources) {
    this(null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 初始化 initializers 属性
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 初始化 listeners 属性
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}
getSpringFactoriesInstances(...)

#getSpringFactoriesInstances(Class<T> type) 方法,获得指定类对应的对象们。代码如下:

java
// SpringApplication.java

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
        Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // Use names and ensure unique to protect against duplicates
    // <1> 加载指定类型对应的,在 `META-INF/spring.factories` 里的类名的数组
    Set<String> names = new LinkedHashSet<>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // <2> 创建对象们
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
    // <3> 排序对象们
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
// SpringApplication.java

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
        Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // Use names and ensure unique to protect against duplicates
    // <1> 加载指定类型对应的,在 `META-INF/spring.factories` 里的类名的数组
    Set<String> names = new LinkedHashSet<>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // <2> 创建对象们
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
    // <3> 排序对象们
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
  • <1>处,调用SpringFactoriesLoader#loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader)

    方法,加载指定类型对应的,在META-INF/spring.factories里的类名的数组。

  • <2> 处,调用 #createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) 方法,创建对象们。

  • <3> 处,调用 AnnotationAwareOrderComparator#sort(List<?> list) 方法,排序对象们。例如说,类上有 @Order 注解。

run()方法解析
java
// SpringApplication.java

public ConfigurableApplicationContext run(String... args) {
   // <1> 创建 StopWatch 对象,并启动。
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();

   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();    

   // <2> 设置java.awt.headless系统属性,默认为true
   // Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。
   configureHeadlessProperty();
    
   // 获得 SpringApplicationRunListener 的数组
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // 通知监听者,开始启动
   listeners.starting();

    try {
        // <3> 创建  ApplicationArguments 对象
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // <4> 加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);
        // <5> 打印 Spring Banner
        Banner printedBanner = printBanner(environment);
        // <6> 创建 Spring 容器
        context = createApplicationContext();
        // <7> 注册异常分析器
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                                                         new Class[] { ConfigurableApplicationContext.class }, context);
        // <8> Spring上下文前置处理-主要是调用所有初始化类的 initialize 方法 
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // <9> Spring上下文刷新-初始化 Spring 容器
        refreshContext(context);
        // <10> 执行 Spring 容器的初始化的后置逻辑。默认实现为空。
        afterRefresh(context, applicationArguments);
        // <11> 停止 StopWatch 统计时长
        stopWatch.stop();
        // <12> 打印 Spring Boot 启动的时长日志。
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        // <13> 通知 SpringApplicationRunListener 的数组,Spring 容器启动完成。
        listeners.started(context);
        // <14> 调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        // <14.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    
    try {
        // <15> 通知 SpringApplicationRunListener 的数组,Spring 容器运行中。
        listeners.running(context);
    }
    catch (Throwable ex) {
        // <15.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}
// SpringApplication.java

public ConfigurableApplicationContext run(String... args) {
   // <1> 创建 StopWatch 对象,并启动。
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();

   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();    

   // <2> 设置java.awt.headless系统属性,默认为true
   // Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。
   configureHeadlessProperty();
    
   // 获得 SpringApplicationRunListener 的数组
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // 通知监听者,开始启动
   listeners.starting();

    try {
        // <3> 创建  ApplicationArguments 对象
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // <4> 加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);
        // <5> 打印 Spring Banner
        Banner printedBanner = printBanner(environment);
        // <6> 创建 Spring 容器
        context = createApplicationContext();
        // <7> 注册异常分析器
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                                                         new Class[] { ConfigurableApplicationContext.class }, context);
        // <8> Spring上下文前置处理-主要是调用所有初始化类的 initialize 方法 
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // <9> Spring上下文刷新-初始化 Spring 容器
        refreshContext(context);
        // <10> 执行 Spring 容器的初始化的后置逻辑。默认实现为空。
        afterRefresh(context, applicationArguments);
        // <11> 停止 StopWatch 统计时长
        stopWatch.stop();
        // <12> 打印 Spring Boot 启动的时长日志。
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        // <13> 通知 SpringApplicationRunListener 的数组,Spring 容器启动完成。
        listeners.started(context);
        // <14> 调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        // <14.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    
    try {
        // <15> 通知 SpringApplicationRunListener 的数组,Spring 容器运行中。
        listeners.running(context);
    }
    catch (Throwable ex) {
        // <15.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}
  • <1> 处,创建 StopWatch 对象,并调用 StopWatch#run() 方法来启动。StopWatch 主要用于简单统计 run 启动过程的时长。

  • <2> 处,配置 headless 属性。这个逻辑,可以无视,和 AWT 相关。

  • <3> 处,调用 #getRunListeners(String[] args) 方法,获得 SpringApplicationRunListener 数组,并启动监听。代码如下:

    java
    // SpringApplication.java
    
    private SpringApplicationRunListeners getRunListeners(String[] args) {
    	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    	return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
    			SpringApplicationRunListener.class, types, this, args));
    }
    // SpringApplication.java
    
    private SpringApplicationRunListeners getRunListeners(String[] args) {
    	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    	return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
    			SpringApplicationRunListener.class, types, this, args));
    }
  • <4> 处,调用 #prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) 方法,加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置

  • <5> 处,调用 #printBanner(ConfigurableEnvironment environment) 方法,打印 Spring Banner 。

  • <6> 处,调用 #createApplicationContext() 方法,创建 Spring 容器

  • <7> 处,通过 #getSpringFactoriesInstances(Class<T> type) 方法,进行获得 SpringBootExceptionReporter 类型的对象数组。SpringBootExceptionReporter ,记录启动过程中的异常信息。

  • <8> 处,调用 #prepareContext(...) 方法,主要是调用所有初始化类的 #initialize(...) 方法。

  • <9> 处,调用 ``#refreshContext(ConfigurableApplicationContext context)` 方法,启动(刷新) Spring 容器

  • <10> 处,调用 #afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) 方法,执行 Spring 容器的初始化的后置逻辑。默认实现为空

  • <11> 处,停止 StopWatch 统计时长。

  • <12> 处,打印 Spring Boot 启动的时长日志。

  • <13> 处,调用 SpringApplicationRunListeners#started(ConfigurableApplicationContext context) 方法,通知 SpringApplicationRunListener 的数组,Spring 容器启动完成。

  • <14> 处,调用 #callRunners(ApplicationContext context, ApplicationArguments args) 方法,调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。

  • <15> 处,调用 SpringApplicationRunListeners#running(ConfigurableApplicationContext context) 方法,通知 SpringApplicationRunListener 的数组,Spring 容器运行中。

SpringBoot注解

条件注解

  • @ConditionalOnBean:当容器里有指定 Bean 的条件下
  • @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
  • @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
  • @ConditionalOnClass:当类路径下有指定类的条件下
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下
  • @ConditionalOnProperty:指定的属性是否有指定的值
  • @ConditionalOnResource:类路径是否有指定的值
  • @ConditionalOnExpression:基于 SpEL 表达式作为判断条件
  • @ConditionalOnJava:基于 Java 版本作为判断条件
  • @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
  • @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
  • @ConditionalOnWebApplication:当前项目是 Web 项 目的条件下

SpringBoot配置文件

加载顺序

当Spring Boot 项目中可以存在多个 application.properties 或 apllication.yml时,Spring Boot 启动时会扫描以下 5 个位置的 application.properties 或 apllication.yml 文件,并将它们作为 Spring boot 的默认配置文件。以下是加载默认配置文件的优先级顺序,从高到底,高优先级的配置可以覆盖低优先级的配置信息:

1> file:./config/*/

2> file:./config/

3> file:./

4> classpath:/config/

5> classpath:/

image-20230110115113929

SpringBooot添加本地 jar

步骤

  1. 添加 jar 文件到项目中 resources/lib/xxx.jar
  2. 安装 jar 包到 maven 本地仓库
xml
<build>
<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-install-plugin</artifactId>
        <version>2.5.2</version>
        <executions>
            <execution>
                <id>install-demo-jar</id>
                <phase>clean</phase>
                <configuration>
                    <file>
                        ${project.basedir}/src/main/resources/lib/demo.jar
                    </file>
                    <groupId>com.javalover</groupId>
                    <artifactId>demo</artifactId>
                    <version>1.0</version>
                    <packaging>jar</packaging>
                    <generatePom>true</generatePom>
                </configuration>
                <goals>
                    <goal>install-file</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>
</build>
<build>
<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-install-plugin</artifactId>
        <version>2.5.2</version>
        <executions>
            <execution>
                <id>install-demo-jar</id>
                <phase>clean</phase>
                <configuration>
                    <file>
                        ${project.basedir}/src/main/resources/lib/demo.jar
                    </file>
                    <groupId>com.javalover</groupId>
                    <artifactId>demo</artifactId>
                    <version>1.0</version>
                    <packaging>jar</packaging>
                    <generatePom>true</generatePom>
                </configuration>
                <goals>
                    <goal>install-file</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>
</build>
  1. 运行 mvn clean