【Spring Boot 源码学习】@EnableAutoConfiguration 注解

简介: 本篇我们一起从源码学习 @EnableAutoConfiguration 注解

微信图片_20231031101034.png

引言

Huazie 的上篇博文中,我们详细了解了关于 @SpringBootApplication 注解 的一些内容,文章最后提到了 @EnableAutoConfiguration 注解,用来开启 Spring Boot 的自动配置功能,这将是本篇将要重点讲解的内容。

主要内容

1. @EnableAutoConfiguration 功能解析

我们知道,在没有使用 Spring Boot 的情况下,Bean 的生命周期都是由 Spring 来管理的,并且 Spring 是无法自动配置 @Configuration 注解的类。Spring Boot 的核心功能之一就是根据约定自动管理 @Configuration 注解的类 ,其中 @EnableAutoConfiguration 注解就是实现该功能的组件之一。

@EnableAutoConfiguration 注解 位于 spring-boot-autoconfigure 包内,当使用 @SpringBootApplication 注解时,它也就会自动生效。
微信图片_20231031102317.png

结合上面的内容,我们很容易猜到 @EnableAutoConfiguration 注解是用来启动 Spring 应用程序上下文时进行自动配置,它会尝试猜测和配置项目可能需要的 Bean

自动配置通常是根据项目中引入的类和已定义的 Bean 来实现的。在自动配置过程中,会检查项目的classpath(类路径)中引入的类以及项目依赖的 jar 包中的组件。

1.1 常见的自动配置示例

下面我们来看看,常见的自动配置的示例,如下所示:

  • 数据库连接池: 假设项目中引入了 Spring BootJDBC Starter 依赖,它会根据类路径中的相关库(如 HikariCP、Durid、Tomcat JDBC等)自动配置数据库连接池。我们只需在配置文件中提供数据库连接的信息,Spring Boot 将会自动创建并配置连接池。

  • Web应用程序: 当引入了 Spring BootWeb Starter 依赖时,它会自动配置嵌入式的 Web 服务器(如 Tomcat、Jetty、 Undertow等),并为我们提供默认的 Web 应用程序上下文和基本的 Web 配置,例如 Servlet、Filter、Listener 等。

  • Spring MVC: 如果在项目中引入了 Spring MVC 的相关依赖,Spring Boot 会自动配置 基于注解的控制器视图解析器异常处理 等,使得开发 Web 应用变得更加简单。

  • 持久化框架集成: 当引入了特定的持久化框架(如 Hibernate、MyBatis 等)的相关依赖时,Spring Boot 会自动配置相应的 SessionFactory事务管理器 等组件,以帮助你进行数据库操作。

  • 安全框架: 当引入了 Spring Security 的相关依赖时,Spring Boot 会自动配置基本的 安全过滤器链用户认证和授权 等,提供基本的应用程序安全性。

1.2 源码介绍

下面我们来看看 @EnableAutoConfiguration 注解的源码【版本:2.7.9】:

/**
 * 启用Spring应用程序上下文的自动配置,尝试猜测和配置可能需要的Bean。
 * 自动配置类通常基于你的类路径和你已定义的Bean来应用。
 * 例如,如果你在类路径中引入了tomcat-embedded.jar,那么很可能希望有一个
 * TomcatServletWebServerFactory(除非你已经定义了自己的ServletWebServerFactory Bean)。
 * 
 * 当使用@SpringBootApplication注解时,上下文的自动配置会自动启用,因此添加此注解没有额外的效果。
 * 
 * 自动配置试图尽可能智能,并且随着你定义更多自己的配置而退避。
 * 你可以手动使用exclude()方法排除任何你不想应用的配置(如果无法访问它们,
 * 则可以使用excludeName()方法)。你还可以通过spring.autoconfigure.exclude属性来排除它们。
 * 自动配置总是在用户自定义的Bean注册之后应用。
 * 
 * 使用@EnableAutoConfiguration注解标注的类所在的包通常具有特殊意义,并且经常被用作"默认"。
 * 例如,在扫描@Entity类时将使用该包。通常建议将@EnableAutoConfiguration(如果你没有使用
 * @SpringBootApplication)放在根包中,以便可以搜索所有子包和类。
 * 
 * 自动配置类是常规的Spring @Configuration Bean。它们是通过ImportCandidates 和
 * SpringFactoriesLoader 机制(针对这个类进行索引)来定位的。通常,自动配置Bean是
 * @Conditional Bean(通常使用@ConditionalOnClass和@ConditionalOnMissingBean注解)。
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @since 1.0.0
 * @see ConditionalOnBean
 * @see ConditionalOnMissingBean
 * @see ConditionalOnClass
 * @see AutoConfigureAfter
 * @see SpringBootApplication
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
   

    /**
     * 可以用于覆盖自动配置是否启用的环境属性
     */
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
     * 排除特定的自动配置类,以使它们永远不会应用
     * @return 要排除的类
     */
    Class<?>[] exclude() default {
   };

    /**
     * 排除特定的自动配置类名,以使它们永远不会应用
     * @return 要排除的类名
     * @since 1.3.0
     */
    String[] excludeName() default {
   };

}

通过查看源码,我们可以看到 @EnableAutoConfiguration 注解提供了一个常量 和 两个成员变量:

  • ENABLED_OVERRIDE_PROPERTY : 用于覆盖自动配置是否启用的环境属性
  • exclude :排除特定的自动配置类
  • excludeName :排除特定的自动配置类名

正如前面所说, @EnableAutoConfiguration 会尝试猜测并配置你可能需要的 Bean,但实际情况如果是我们不需要这些预配置的 Bean,那么也可以通过它的两个成员变量 excludeexcludeName 来排除指定的自动配置。

// 通过 @SpringBootApplication 排除 DataSourceAutoConfiguration
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class DemoApplication {
   

}

或者:

// 通过 @EnableAutoConfiguration 排除 DataSourceAutoConfiguration
@Configuration
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
public class DemoConfiguration {
   
}

注意:
Spring Boot 在进行实体类扫描时,会从 @EnableAutoConfiguration 注解标注的类所在的包开始扫描。这也是在使用 @SpringBootApplication 注解时需要将被注解的类放在顶级 package 下的原因,如果放在较低层级,它所在 package 的同级或上级中的类就无法被扫描到,从而无法正常使用相关注解(如 @Entity)。

从我们上篇博文中新建的 Spring Boot 项目可知,@SpringBootApplication 注解通常用于标记 Spring Boot 应用程序的入口类。它会自动启用 Spring Boot 的自动配置和组件扫描等功能。但是,如果你希望将自动配置应用于其他类,而不是入口类本身,那么你可以将 @SpringBootApplication 注解添加到这些类上。同样地,@EnableAutoConfiguration 注解也可以用于其他类,而不仅限于入口类。这个注解用于启用Spring 的自动配置功能,并根据类路径和已定义的Bean来自动配置应用程序上下文。

因此,在 Spring Boot 应用程序中,入口类只是一个用来引导应用程序的类,而真正的自动配置和功能开启是通过 @SpringBootApplication@EnableAutoConfiguration 注解所用的其他类完成的。

2. @Import 注解介绍

从上面 @EnableAutoConfiguration 注解的源码可知,@Import(AutoConfigurationImportSelector.class) 也是@EnableAutoConfiguration 注解的组成部分,这也是自动配置功能的核心实现者。

下面我们重点讲解一下 @Import 注解,至于它对应的 ImportSelector ,我们将在后续的博文中详细介绍。

@Import 注解位于 spring-context 项目内,主要提供导入配置类的功能。在后续的学习源码的过程中,我们会发现有大量的 EnableXXX 类使用了@Import 注解。

下面我们来看一下 @Import 的源码【版本 spring-context-5.3.25】:

/**
 * 指示导入一个或多个组件类,通常是@Configuration类。
 * 
 * 提供与Spring XML中的<import/>元素相当的功能。允许导入@Configuration类、
 * ImportSelector 和 ImportBeanDefinitionRegistrar 实现,以及普通的组件类
 * (从4.2开始;类似于AnnotationConfigApplicationContext.register)。
 * 
 * 在导入的 @Configuration 类中声明的@Bean定义应该通过@Autowired注入来访问。
 * 可以将bean本身进行自动装配,也可以将声明bean的配置类实例进行自动装配。
 * 后一种方法允许在@Configuration类方法之间进行显式且友好的导航(适用于IDE)。
 * 
 * 可以在类级别或作为元注解进行声明。
 * 
 * 如果需要导入XML或其他非 @Configuration 的bean定义资源,请使用 @ImportResource 注解来实现。
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.0
 * @see Configuration
 * @see ImportSelector
 * @see ImportBeanDefinitionRegistrar
 * @see ImportResource
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
   

    /**
     * @Configuration、ImportSelector、ImportBeanDefinitionRegistrar 或常规组件类可以用来进行导入。
     */
    Class<?>[] value();

}

上面的源码注释中,已经将 @Import 注解上的英文注释翻译成了中文注释,大家可以阅读了解下,这里就不再展开介绍了。

3. @AutoConfigurationPackage 注解介绍

细心的朋友可能发现了,在 @EnableAutoConfiguration 注解的源码中,还有一个 @AutoConfigurationPackage 注解。

那么 @AutoConfigurationPackage 注解有啥作用呢?

在解答之前,我们先来看看 @AutoConfigurationPackage 注解的源码【版本 2.7.9 】:

/**
 * 将包注册到 AutoConfigurationPackages 中。
 * 当没有指定基础包或基础包类时,将会注册带有注解类的包。
 *
 * @author Phillip Webb
 * @since 1.3.0
 * @see AutoConfigurationPackages
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
   

    /**
     * 应该注册到 AutoConfigurationPackages 的基础包。
     * 使用 basePackageClasses 作为基于类型安全的替代方法,而不是基于字符串的包名。
     * 
     * @since 2.3.0
     */
    String[] basePackages() default {
   };

    /**
     * @AutoConfigurationPackage 提供了一种类型安全的替代方案,用于指定要注册到 AutoConfigurationPackages 的包。
     * 考虑在每个包中创建一个特殊的无操作标记类或接口,除了被此属性引用外,不具备任何其他功能。
     * 
     * @since 2.3.0
     */
    Class<?>[] basePackageClasses() default {
   };

}

通过上述阅读源码,我们可以看到 @AutoConfigurationPackage 上有如下这段代码:

@Import(AutoConfigurationPackages.Registrar.class)

通过上面的 @Import 注解介绍,我们可以知道,这段代码的作用其实就是通过导入AutoConfigurationPackages.Registrar 类【其中 ImportBeanDefinitionRegistrar 用于存储导入配置的基础包信息】,将基础包及其子包注册到 AutoConfigurationPackages 中,以便实现自动配置的功能。

通常情况下,Spring Boot 应用程序会将主配置类(例如使用 @SpringBootApplication 注解的类)置于根包中。这样做的话,根包会作为默认的扫描路径,用于自动发现和注册 Spring 组件(如@Controller、@Service、@Repository 等)。

当使用 @AutoConfigurationPackage 注解时,它会将指定类所在的包及其子包中的组件自动注册到Spring应用程序上下文中,即自动装配这些组件,从而简化了组件的配置和使用。

总结

本篇笔者介绍了 @EnableAutoConfiguration 注解的相关功能,当然其中真正实现自动配置功能的核心实现者 AutoConfigurationImportSelector 还没有详细说明,那下一篇博文我们将重点对 AutoConfigurationImportSelector 的源码进行学习,敬请期待!!!

目录
相关文章
|
5天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
22小时前
|
Java 应用服务中间件 测试技术
深入探索Spring Boot Web应用源码及实战应用
【5月更文挑战第11天】本文将详细解析Spring Boot Web应用的源码架构,并通过一个实际案例,展示如何构建一个基于Spring Boot的Web应用。本文旨在帮助读者更好地理解Spring Boot的内部工作机制,以及如何利用这些机制优化自己的Web应用开发。
7 2
|
1天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
3天前
|
存储 前端开发 Java
Spring Boot自动装配的源码学习
【4月更文挑战第8天】Spring Boot自动装配是其核心机制之一,其设计目标是在应用程序启动时,自动配置所需的各种组件,使得应用程序的开发和部署变得更加简单和高效。下面是关于Spring Boot自动装配的源码学习知识点及实战。
13 1
|
4天前
|
JavaScript Java 开发者
Spring Boot中的@Lazy注解:概念及实战应用
【4月更文挑战第7天】在Spring Framework中,@Lazy注解是一个非常有用的特性,它允许开发者控制Spring容器的bean初始化时机。本文将详细介绍@Lazy注解的概念,并通过一个实际的例子展示如何在Spring Boot应用中使用它。
17 2
|
4天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
46 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
5天前
|
前端开发 Java
SpringBoot之自定义注解参数校验
SpringBoot之自定义注解参数校验
16 2
|
2月前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
53 0
|
2月前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
137 0
|
1月前
|
存储 JSON Java
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间
43 2