跳转至

Spring的Bean相关知识及Spring Boot自动配置

约 1675 个字 401 行代码 2 张图片 预计阅读时间 11 分钟

Bean的作用域

Bean的六种作用域与演示,除了不演示websocket(比较麻烦,不过可以进一步研究一下ServletContext作用域,结合微服务)

根据官方文档的介绍,Bean有六种作用域,分别是:singleton(单例)、prototype(原型)、request(请求)、session(会话)、application(全局)和 websocket,其中后四种需要在 Web 环境下生效

测试代码:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.epsda.springprinciple.model;

import lombok.Getter;
import lombok.Setter;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 18483
 * Date: 2026/07/27
 * Time: 9:51
 *
 * @Author: 憨八嘎
 */
@Getter
@Setter
public class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }
}
Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package org.epsda.springprinciple.config;

import org.epsda.springprinciple.model.Student;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.web.context.annotation.ApplicationScope;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.context.annotation.SessionScope;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 18483
 * Date: 2026/07/27
 * Time: 9:55
 *
 * @Author: 憨八嘎
 */
@Configuration
public class StudentConfig {

    // 单例
    @Bean("single")
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public Student student1() {
        return new Student("张三");
    }

    // 多例
    @Bean("prototype")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Student student2() {
        return new Student("李四");
    }

    // 请求
    @Bean("request")
    @RequestScope // 相当于@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Student student3() {
        return new Student("王五");
    }

    // 会话
    @Bean("session")
    @SessionScope // 相当于@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Student student4() {
        return new Student("赵六");
    }

    // Servlet
    @Bean("servlet")
    @ApplicationScope // 相当于@Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Student student5() {
        return new Student("田七");
    }
}
Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package org.epsda.springprinciple.controller;

import jakarta.annotation.Resource;
import org.epsda.springprinciple.model.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 18483
 * Date: 2026/07/27
 * Time: 10:03
 *
 * @Author: 憨八嘎
 */
@RequestMapping("/student")
@RestController
public class StudentController {
    @Resource(name = "single")
    private Student singleStudent;
    @Resource(name = "prototype")
    private Student prototypeStudent;
    @Resource(name = "request")
    private Student requestStudent;
    @Resource(name = "session")
    private Student sessionStudent;
    @Resource(name = "servlet")
    private Student servletStudent;
    @Resource
    private ApplicationContext context;

    @RequestMapping("/single")
    public String s1() {
        // 先从容器里拿
        Student single = (Student) context.getBean("single");
        return "获取到Student对象:" + singleStudent.getName() + ",地址为:" + singleStudent + ",容器中的对象为:" + single;
    }

    @RequestMapping("/prototype")
    public String s2() {
        Student student = (Student) context.getBean("prototype");
        return "获取到Student对象:" + prototypeStudent.getName() + ",地址为:" + prototypeStudent + ",容器中的对象为:" + student;
    }

    @RequestMapping("/request")
    public String s3() {
        Student student = (Student) context.getBean("request");
        return "获取到Student对象:" + requestStudent.getName() + ",地址为:" + requestStudent + ",容器中的对象为:" + student;
    }

    @RequestMapping("/session")
    public String s4() {
        Student student = (Student) context.getBean("session");
        return "获取到Student对象:" + sessionStudent.getName() + ",地址为:" + sessionStudent + ",容器中的对象为:" + student;
    }

    @RequestMapping("/servlet")
    public String s5() {
        Student student = (Student) context.getBean("servlet");
        return "获取到Student对象:" + servletStudent.getName() + ",地址为:" + servletStudent + ",容器中的对象为:" + student;
    }
}

下面是除了websocket作用域以外的五种作用域测试结果:

Java
1
2
3
4
5
获取到Student对象张三地址为org.epsda.springprinciple.model.Student@1400493b容器中的对象为org.epsda.springprinciple.model.Student@1400493b

获取到Student对象张三地址为org.epsda.springprinciple.model.Student@1400493b容器中的对象为org.epsda.springprinciple.model.Student@1400493b

获取到Student对象张三地址为org.epsda.springprinciple.model.Student@1400493b容器中的对象为org.epsda.springprinciple.model.Student@1400493b

prototype测试结果

Java
1
2
3
4
5
获取到Student对象李四地址为org.epsda.springprinciple.model.Student@7a6e2809容器中的对象为org.epsda.springprinciple.model.Student@46a439aa

获取到Student对象李四地址为org.epsda.springprinciple.model.Student@7a6e2809容器中的对象为org.epsda.springprinciple.model.Student@3732c321

获取到Student对象李四地址为org.epsda.springprinciple.model.Student@7a6e2809容器中的对象为org.epsda.springprinciple.model.Student@2a5c99cf

注入的对象当Spring程序启动之后就已经确定了对象,所以一直保持不变。但是容器中是每一次取一个新的,所以地址一直在改变

Java
1
2
3
4
5
获取到Student对象王五地址为org.epsda.springprinciple.model.Student@4e410f9d容器中的对象为org.epsda.springprinciple.model.Student@4e410f9d

获取到Student对象王五地址为org.epsda.springprinciple.model.Student@e007e14容器中的对象为org.epsda.springprinciple.model.Student@e007e14

获取到Student对象王五地址为org.epsda.springprinciple.model.Student@7ca5c255容器中的对象为org.epsda.springprinciple.model.Student@7ca5c255

request 作用域的 Bean 由作用域代理(scoped proxy)承载,每次 HTTP 请求进来,代理再去当前请求的 RequestAttributes 里取真正的 Student(注入的对象实际上并不是真正的Student对象),即每个请求都会新建一个真实实例,所以注入的对象和每次从容器中获取的对象都是同一个

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 同一个客户端重复发起三次请求
获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@1f0aee7d容器中的对象为org.epsda.springprinciple.model.Student@1f0aee7d

获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@1f0aee7d容器中的对象为org.epsda.springprinciple.model.Student@1f0aee7d

获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@1f0aee7d容器中的对象为org.epsda.springprinciple.model.Student@1f0aee7d

// 关闭客户端后重新请求
获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@571d3c6e容器中的对象为org.epsda.springprinciple.model.Student@571d3c6e

获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@571d3c6e容器中的对象为org.epsda.springprinciple.model.Student@571d3c6e

获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@571d3c6e容器中的对象为org.epsda.springprinciple.model.Student@571d3c6e

// 切换客户端重新请求
获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@329bba7f容器中的对象为org.epsda.springprinciple.model.Student@329bba7f

获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@329bba7f容器中的对象为org.epsda.springprinciple.model.Student@329bba7f

获取到Student对象赵六地址为org.epsda.springprinciple.model.Student@329bba7f容器中的对象为org.epsda.springprinciple.model.Student@329bba7f

session和request比较类似,但是session的范围比request大,session不局限于一个请求,而是一个JSESSIONID对应着一个客户端,所以只要JSESSIONID一致,不论请求多少次都是通过同一个代理获取到对象

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 不同客户端多次请求
获取到Student对象田七地址为org.epsda.springprinciple.model.Student@1da7a93容器中的对象为org.epsda.springprinciple.model.Student@1da7a93

获取到Student对象田七地址为org.epsda.springprinciple.model.Student@1da7a93容器中的对象为org.epsda.springprinciple.model.Student@1da7a93

获取到Student对象田七地址为org.epsda.springprinciple.model.Student@1da7a93容器中的对象为org.epsda.springprinciple.model.Student@1da7a93

获取到Student对象田七地址为org.epsda.springprinciple.model.Student@1da7a93容器中的对象为org.epsda.springprinciple.model.Student@1da7a93

获取到Student对象田七地址为org.epsda.springprinciple.model.Student@1da7a93容器中的对象为org.epsda.springprinciple.model.Student@1da7a93

获取到Student对象田七地址为org.epsda.springprinciple.model.Student@1da7a93容器中的对象为org.epsda.springprinciple.model.Student@1da7a93

// 不同的Spring Boot应用
获取到Student对象田七地址为org.epsda.springprinciple.model.Student@6fd11976容器中的对象为org.epsda.springprinciple.model.Student@6fd11976

因为servlet对应的是一个Spring应用,只要是同一个应用,获取到的对象都是一样的。但是需要注意servlet与singleton的区别:servlet作用域是ServletContext级别的单例,而singleton是ApplicationContext级别的单例,在一个Web容器中可以有多个ApplicationContext,所以对于不同的Web容器,同一个类也会有多个单例对象

Bean的生命周期

简单了解生命周期的过程

  1. 实例化:Spring 通过反射调用构造方法创建 Bean 对象,但是这个时候还没有任何的属性内容
  2. 属性注入:通过 setter 方法或字段反射把依赖的其他 Bean 塞进去
  3. Aware 接口回调:如果 Bean 实现了 BeanNameAwareBeanFactoryAwareApplicationContextAware 这些接口,Spring 会把对应的容器信息注入进来
  4. BeanPostProcessor 前置处理:所有 BeanPostProcessorpostProcessBeforeInitialization 方法会被调用
  5. 初始化:按顺序执行 @PostConstruct 注解方法、InitializingBeanafterPropertiesSet 方法、@Bean 指定的initMethod
  6. BeanPostProcessor 后置处理:所有 BeanPostProcessorpostProcessAfterInitialization 方法会被调用,AOP 代理通常就在这一步生成
  7. Bean 就绪:可以被其他组件使用了
  8. 销毁:容器关闭时按顺序执行 @PreDestroy 注解方法、DisposableBeandestroy 方法、@Bean 指定的destroyMethod

参考图如下:

Spring Boot加载非本包下的自定义配置类

概览

在Spring中,可以通过下面几种方式实现加载第三方包中的类:

  1. 启动类上使用@ComponentScan,其中的basePackagebasePackages即可配置包路径
  2. 使用@Import注解,直接导入第三方配置类的 class 对象
  3. 自定义类实现ImportSelector接口,通过Import注解导入,结合自定义注解实现快速导入
  4. 创建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件并写入需要Spring帮忙扫描的包路径

创建一个第三方包和类:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package org.epsda.diyconfig;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SelfConfig {

    public void use() {
        System.out.println("使用自定义配置");
    }
}

以上面的配置类为例演示上面的四种方式

@ComponentScan 方式

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 使用@ComponentScan,注意观察第三方配置类所在的包和启动程序所在的包
package org.epsda.springprinciple;

import org.epsda.diyconfig.SelfConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan("org.epsda.diyconfig")
@SpringBootApplication
public class SpringPrincipleApplication {
    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringPrincipleApplication.class, args);

        SelfConfig config = (SelfConfig) applicationContext.getBean("selfConfig");
        config.use();
    }
}

但是需要注意的是,上面的代码只是在@ComponentScan中配置扫描了org.epsda.diyconfig,此时原来默认扫描启动程序所在包的行为就没了,所以一般情况下都是配置当前启动程序所在的包以及第三方配置的包:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.epsda.springprinciple;

import org.epsda.diyconfig.SelfConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;

// 配置启动类所在的包和第三方配置所在的包
@ComponentScan(basePackages = {
        "org.epsda.diyconfig",
        "org.epsda.springprinciple" 
})
@SpringBootApplication
public class SpringPrincipleApplication {
    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringPrincipleApplication.class, args);

        SelfConfig config = (SelfConfig) applicationContext.getBean("selfConfig");
        config.use();
    }
}

@Import 方式

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.epsda.springprinciple;

import org.epsda.diyconfig.SelfConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;

import java.util.Arrays;

@Import(SelfConfig.class)
@SpringBootApplication
public class SpringPrincipleApplication {
    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringPrincipleApplication.class, args);

        // 使用下面的代码查看类的Bean名称
        // String[] beanNamesForType = applicationContext.getBeanNamesForType(SelfConfig.class);
        // System.out.println(Arrays.toString(beanNamesForType));
        // 需要注意,使用@Import导入,Bean的名称必须为类的全限定名
        SelfConfig config = (SelfConfig) applicationContext.getBean("org.epsda.diyconfig.SelfConfig");
        config.use();
    }
}

@Import最大的缺点就是需要一个一个导入,如果有多个配置类需要导入就需要写多个@Import

实现ImportSelector

使用ImportSelector接口实现类,可以在selectImports方法中返回需要导入的配置类的全限定类名数组,从而一次性导入多个配置类。这种方式比逐个使用@Import更加灵活,也便于结合自定义注解实现批量导入

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package org.epsda.springprinciple;

import org.epsda.diyconfig.SelfConfig;
import org.epsda.diyconfig.SelfImportSelector;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;

@Import(SelfImportSelector.class) // 此时只需要导入实现ImportSelector的类
@SpringBootApplication
public class SpringPrincipleApplication {
    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringPrincipleApplication.class, args);

        // 需要注意,使用@Import导入,Bean的名称必须为类的全限定名
        SelfConfig config = (SelfConfig) applicationContext.getBean("org.epsda.diyconfig.SelfConfig");
        config.use();
    }
}

上面的使用方式还是相对繁琐,在常规的使用中,一般会配合自定义主键进行使用,例如:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package org.epsda.diyconfig;

import org.springframework.context.annotation.Import;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(SelfImportSelector.class) // 自定义注解引入
public @interface EnableSelfConfig {
}

接着在启动类上使用自定义注解

Java
1
2
3
4
5
6
7
8
9
@EnableSelfConfig // 使用自定义注解
@SpringBootApplication
public class SpringPrincipleApplication {
    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringPrincipleApplication.class, args);
        SelfConfig config = (SelfConfig) applicationContext.getBean("org.epsda.diyconfig.SelfConfig");
        config.use();
    }
}

使用Spring配置文件

在第三方配置包下的resources目录添加META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件:

文件中可以写入SelfConfig类或者SelfImportSelector类:

Java
1
org.epsda.diyconfig.SelfImportSelector

直接启动主程序即可看到可以正常识别到自定义配置类

Spring Boot的自动配置

核心流程

自动配置的核心在于 Spring Boot 启动时,通过 @EnableAutoConfiguration 注解,利用 AutoConfigurationImportSelector 加载 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中定义的配置类,并结合 @Conditional 系列注解进行条件过滤,最终将有条件的、符合当前环境依赖的 Bean 自动注入到 IoC 容器中

自动配置和自动装配的区别

自动装配(Autowiring) 自动配置(Auto-configuration)
解决的问题 已存在的 Bean 之间,依赖怎么注入 根据 classpath 和配置,决定要不要创建某个 Bean
属于 Spring Framework 核心(DI 的一部分) Spring Boot 独有
触发点 @Autowired / @Resource / 构造器注入 @EnableAutoConfiguration(藏在 @SpringBootApplication 里)
发生时机 每个 Bean 创建时填属性 容器启动、扫描配置阶段

源码查看

进入@EnableAutoConfiguration注解的内部,核心是@Import(AutoConfigurationImportSelector.class),它会去读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中定义的配置类,有条件地将其导入到IoC容器中

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@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

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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());
    }
}

进入getAutoConfigurationEntry方法:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

进入getCandidateConfigurations方法,该方法会读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsMETA-INF/spring.factories两个文件中定义的所有自动配置类,并将它们返回作为候选配置集合:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation,
            getBeanClassLoader());
    List<String> configurations = importCandidates.getCandidates();
    Assert.state(!CollectionUtils.isEmpty(configurations),
            "No auto configuration classes found in " + "META-INF/spring/"
                    + this.autoConfigurationAnnotation.getName() + ".imports. If you "
                    + "are using a custom packaging, make sure that file is correct.");
    return configurations;
}

进入load方法:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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());
    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);
}

自动配置的过滤与条件装配

通过getCandidateConfigurations方法获取到的自动配置类数量非常多,但并不是所有配置类都会被加载到IoC容器中。Spring Boot在getAutoConfigurationEntry方法中会通过getConfigurationClassFilter().filter(configurations)对候选配置类进行过滤,这个过滤机制会结合每个自动配置类上的@Conditional系列注解(如@ConditionalOnClass@ConditionalOnMissingBean@ConditionalOnProperty等)来判断当前环境中是否满足该配置类的生效条件,只有满足所有条件注解的配置类才会被最终导入,从而实现按需加载和有条件装配。

例如下面的测试代码:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Configuration
@ConditionalOnClass(DataSource.class)  // classpath 里有 DataSource 类才生效
@ConditionalOnMissingBean(DataSource.class)  // 容器里没有 DataSource Bean 才生效
@ConditionalOnProperty(prefix = "spring.datasource", name = "url")  // 配置文件里有这个属性才生效
public class DataSourceAutoConfiguration {
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

禁用自动配置的几种方式

概览

  1. 在启动类上进行排除
  2. 在配置文件中进行排除

在启动类上进行排除

Java
1
2
3
4
5
6
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) // 不加载DataSourceAutoConfiguration
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

在配置文件中进行排除

YAML
1
2
3
4
spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration