一、引言

不知道大家有没有想过这样一个问题,关于我们的 Spring Boot 啊,前面很多地方我都是说 Spring 帮我们做的,那他到底是怎么帮我们做的呢?就比如我们的启动类,叫什么 XXXX Application,那大家有没有想过,为什么这个启动类就能启动我们整个程序呢?那我们换一个名字可不可以?就一定要叫 某某某Application 吗?带着这些疑问,深入的走进我的这篇博文吧。


二、Spring 加载 Bean

不知道各位程序猿有没有想过,Spring 是如何加载 Bean 的呢?比如说我们设置 Bean 类型的时候,就只需要声明注解就行了,Spring 就能帮助我们这个类,那 Spring 究竟是如何管理、如何添加到 Spring 里面的呢?其实这些工作在我们启动程序的时候就已经做好了,想要知道怎么做的,那我们就要先弄明白启动类 -> XXXX Application 是怎么回事,我们可以改一下启动类的路径,如下:

Spring Boot 的自动配置_子类

正常来说,我们只需要访问 "127.0.0.1:8080/blog/b1" 这个地址的话就可以看到 "b1 test" 这段信息了,但是通过我们的访问发现,页面出现了这种情况:

Spring Boot 的自动配置_子类_02

它报了一个 404 的错,但是我们检查发现,我们的 url 并没有出现问题,这就是我们的启动类没有扫描到这个 Bean 出现的问题了,我们可以点进 @SpringBootApplication 这个注解去看看到底怎么回事,如下:

2.1、元注解

Spring Boot 的自动配置_Spring Boot自动配置_03

  1. @Target({ElementType.TYPE})
  • 作用@Target 注解用于指定被注解的注解可以应用的Java元素类型。换句话说,它限制了你的注解可以放在哪里。
  • 参数ElementType 是一个枚举类型,包含了许多表示Java元素的常量,如 TYPEMETHODFIELD 等。在这个例子中,{ElementType.TYPE} 表示注解只能被用于类、接口(包括注解类型)或枚举声明上。
  • 示例:如果你有一个注解被 @Target({ElementType.TYPE}) 修饰,那么它就不能被用于方法或字段上,只能被用于类、接口或枚举上。
  1. @Retention(RetentionPolicy.RUNTIME)
  • 作用:如上所述,@Retention 注解用于指定被注解的注解的保留策略。
  • 参数RetentionPolicy.RUNTIME 表示注解在运行时可通过反射机制读取。这是最常见的保留策略之一,因为它允许程序在运行时查询注解信息。
  • 示例:如果你的注解需要被反射API在运行时访问,你应该使用 @Retention(RetentionPolicy.RUNTIME)
  1. @Documented
  • 作用:如上所述,@Documented 注解指示被注解的注解应该被 javadoc 或类似的工具文档化。
  • 参数@Documented 注解没有参数。
  • 示例:如果你的注解包含了一些重要的信息,并且你希望这些信息能够出现在使用了你注解的元素的文档中,那么你应该使用 @Documented
  1. @Inherited
  • 作用@Inherited 注解表示被注解的注解将具有继承性。如果某个类使用了某个带有 @Inherited 注解的注解,那么这个类的子类也将自动继承该注解,而无需显式声明。
  • 参数@Inherited 注解没有参数。
  • 示例:假设你有一个注解 @MyInheritedAnnotation 被 @Inherited 修饰,并且它被用在了类 BaseClass 上。那么,任何继承自 BaseClass 的子类都将自动继承 @MyInheritedAnnotation 注解,即使这些子类没有显式地使用这个注解。

大家不用太深究这些元注解,知道个大概就行,主要看下面的那三个注解。

2.2、其他注解

首先就是上面说的启动类那个,@ComponentScan 这个注解就是标识是扫描路径的,可以通过 basePackageClasses 或 basePackages 来定义要扫描的特定包, 如果没有定义特定的包,将从声明该注解的类的包开始扫描,这也是为什么 Spring Boot 项目声明的注解类必须要在启动类的目录下。如何定义呢?如下:

@SpringBootApplication
@ComponentScan("com.zmbdp.blogtest")// 自定义扫描路径,全限定名称
public class BlogTestApplication {
    public static void main(String[] args) {
        SpringApplication.run(BlogTestApplication.class, args);
    }
}

这样设置之后就可以扫描到了,结果如下:

Spring Boot 的自动配置_web启动类_04

然后就是我们的 @SpringBootConfiguration 注解了,其实这个注解点进去之后会发现,是这样的:Spring Boot 的自动配置_配置文件_05,里面有个 @Configuration 注解,说明这标识着就是一个 @Configuration 类,只不过给 Spring 包装了一下,增加了一些功能(了解即可)。

2.3、@EnableAutoConfiguration 注解

接下来就是比较重要的 @EnableAutoConfiguration 注解了,这是一个通过检查类路径中的依赖和配置来自动配置 Spring 应用程序,然后就会看你设置的 application.propertiesapplication.yml,导入两个地方的,一个地方是 META-INF/spring.factories 配置文件。这个配置文件包含了 Spring Boot 自动配置类的列表,这些类根据项目的依赖和配置自动注册到 Spring 容器中。还有一个地方是 org.springframework.boot.autoconfigure.AutoConfiguration.imports 这个文件是加载其他你需要的一些依赖,如下:

Spring Boot 的自动配置_web启动类_06

还是有些能看明白的,比如说 data 啊,cache(验证码),aop 这些。

讲到这里,这个 Spring 的启动类的自动配置这块算是差不多弄明白了。


三、总结

通过这篇文章,我们深入探讨了 Spring Boot 启动类的奥秘,了解了 Spring 是如何通过一系列注解和自动配置机制来加载和管理 Bean 的。在这其中,@SpringBootApplication、@ComponentScan、@EnableAutoConfiguration 等注解起到了至关重要的作用,它们帮助我们简化了配置过程,让我们能够更加专注于业务逻辑的开发。通过理解这些背后的原理,不仅能帮助我们更好地掌握 Spring Boot 的核心机制,还能在实际开发中更加灵活地运用这些工具,提升开发效率。


四、结语

Spring Boot 不仅仅是简化开发的工具,更是我们深入掌握技术、提升编程思维的伙伴。通过探究它的启动原理,我们不仅解开了神秘的面纱,也收获了驾驭复杂系统的信心。未来的开发道路上,希望大家能带着好奇心与探索精神,不断突破自我边界,拥抱未知的挑战。技术的世界广阔而深邃,只有不断求知和钻研,才能在这片领域中留下属于自己的印记。