Spring Boot原理分析(一):项目启动流程、自动装配

news2024/11/26 18:54:48

文章目录

  • 一、项目启动流程
  • 二、SpringBootApplication.java源码解析
    • 1.准备工作
    • 2.源码
    • 3.自定义注解
    • 4.组合注解
    • 5.注解@ComponentScan
      • 过滤器
    • 6.注解@SpringBootConfiguration
      • @Configuration
    • 7.注解@EnableAutoConfiguration
      • (1)Spring手动装配
        • 使用XML配置文件
        • 使用Java注解
        • 使用Java类
      • (2)Spring Boot自动装配
        • @AutoConfigurationPackage
        • @Import(AutoConfigurationImportSelector.class)

本文章是Spring Boot原理分析系列博客的第一篇,将会介绍一些准备工作和Spring Boot的项目启动的原理和源码。

一、项目启动流程

  1. 加载Spring Boot的启动类: Spring Boot应用程序的入口点是一个带有@SpringBootApplication注解的Java类。该注解会触发Spring Boot的自动配置和组件扫描。

  2. 创建Spring应用程序上下文: 在启动类中,使用SpringApplication.run()方法创建一个Spring应用程序上下文。该方法会加载所有的配置、组件和依赖,并创建一个可用于管理应用程序的上下文对象。

  3. 执行自动装配: Spring Boot会根据类路径上的依赖和配置,自动配置应用程序的各个组件。它会根据约定和默认值,自动配置数据库连接、Web服务器、日志记录等功能。

  4. 启动内嵌的Web服务器: 如果应用程序是一个Web应用程序,Spring Boot会自动启动一个内嵌的Web服务器(如Tomcat、Jetty等),并将应用程序部署到该服务器上。

  5. 运行应用程序: 一旦所有的配置和组件都加载完毕,Spring Boot会调用应用程序的主要方法,开始执行应用程序的业务逻辑。

二、SpringBootApplication.java源码解析

1.准备工作

  • 环境:
jdk 1.8 + Maven 3.3.9或以上版本 + IDEA
SpringBoot 2.7.13
  • 启动类:
    创建项目后会自动创建一个启动类,运行main方法就可以启动项目,代码如下:
package tracy.springbootcode;

@SpringBootApplication
public class SpringBootCodeApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootCodeApplication.class, args);
    }

}

可以说,@SpringBootApplication是其中最关键的东西。

2.源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};


	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};
	
	@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;
}

3.自定义注解

关于自定义注解的相关知识可以先看我这篇博客了解一下。

以下四个元注解用于定义@SpringBootApplication这个注解:

@Target(ElementType.TYPE)//注解的作用目标是类、接口(包括注解类型)或枚举声明。
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited//此注解可被继承

4.组合注解

@SpringBootApplication是一个组合注解,它等价于同时标注 @Configuration + @EnableAutoConfiguration + @ComponentScan 。

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
	...
}

在这里插入图片描述

5.注解@ComponentScan

可以指定包扫描的根路径,让 SpringFramework 来扫描指定包及子包下的组件;也可以不指定路径,默认扫描当前配置类所在包及子包里的所有组件,所以启动类才会放到所有类所在包的最外层。

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

过滤器

这段代码是使用Spring框架中的注解来指定Spring Boot自动配置时需要排除的类。

具体来说,这里使用了两个@Filter注解,分别指定了需要排除的类的类型以及具体的类名:

  • 第一个@Filter注解的type属性值为FilterType.CUSTOM,表示需要使用自定义的过滤器来进行过滤;
    classes属性指定了具体的自定义过滤器类,这里是TypeExcludeFilter.class。 它会从 BeanFactory (可以暂时理解成IOC容器)中获取所有类型为 TypeExcludeFilter 的组件,去执行自定义的过滤方法。由此可见,TypeExcludeFilter 的作用是做扩展的组件过滤。

  • 第二个@Filter注解同样是type属性值为FilterType.CUSTOM,表示需要使用自定义过滤器;
    classes属性指定了另一个自定义过滤器类,这里是AutoConfigurationExcludeFilter.class。会将不需要自动配置的类屏蔽掉。

这两个自定义过滤器的作用是根据一定的规则来排除不需要自动配置的类。例如,TypeExcludeFilter可以排除特定类型的类,AutoConfigurationExcludeFilter可以排除不需要自动配置的类。这样就可以在Spring Boot自动配置过程中,针对某些类进行自定义的过滤和排除,从而更加灵活地控制自动配置的行为。

6.注解@SpringBootConfiguration

  • @SpringBootConfiguration的定义:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

@SpringBootConfiguration被 @Configuration 标注,说明它实际上是标注配置类的,而且是标注主启动类的。

也就是说,在启动类上使用这个注解表明该类是一个配置类,也是当前项目的主启动类。

@Configuration

被 @Configuration 标注的类,会被 Spring 的IOC容器认定为配置类。一个被 @Configuration 标注的类,相当于一个 applicationContext.xml 的配置文件。

7.注解@EnableAutoConfiguration

这一个注解是spring boot自动装配的核心注解。

(1)Spring手动装配

Spring Framework提供了多种手动装配的方式,其中比较常见的有以下几种:

使用XML配置文件

在XML配置文件中使用<bean>元素配置需要装配的Bean对象,然后使用ClassPathXmlApplicationContext或者XmlWebApplicationContext启动Spring容器。Spring容器会自动解析XML配置文件,并将其中配置的Bean对象注册为Spring容器中的Bean对象。

示例代码如下:

<beans>
    <bean id="myService" class="com.example.service.MyServiceImpl"/>
    <bean id="myController" class="com.example.controller.MyController">
        <property name="myService" ref="myService"/>
    </bean>
</beans>

使用Java注解

在Java类中使用@Configuration注解标记一个配置类,然后在该类中使用@Bean注解标记需要装配的Bean对象。然后使用AnnotationConfigApplicationContext启动Spring容器。Spring容器会自动扫描@Configuration注解的类,并将其中使用@Bean注解标记的方法的返回值注册为Spring容器中的Bean对象。

示例代码如下:

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }

    @Bean
    public MyController myController() {
        MyController controller = new MyController();
        controller.setMyService(myService());
        return controller;
    }
}

使用Java类

直接在Java类中创建需要装配的Bean对象,并将其注册到Spring容器中。然后使用AnnotationConfigApplicationContext启动Spring容器。Spring容器会自动扫描Java类中注册的Bean对象,并将其注册为Spring容器中的Bean对象。

示例代码如下:

public class MyConfig {
    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }

    @Bean
    public MyController myController() {
        MyController controller = new MyController();
        controller.setMyService(myService());
        return controller;
    }
}

public class MyApp {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        MyController controller = context.getBean(MyController.class);
        // ...
    }
}

需要注意的是,Spring Framework的手动装配方式适用于需要对Bean进行复杂的配置或者需要根据特定条件进行Bean的选择和装配的场景。对于简单的Bean对象,使用自动装配方式更加方便快捷。

(2)Spring Boot自动装配

SpringBoot的自动配置完全由 @EnableAutoConfiguration 开启,这一注解是上一篇博客中所介绍的@SpringBootApplication注解中的组成之一。

在这里插入图片描述

从@EnableAutoConfiguration的定义可以看出,@AutoConfigurationPackage注解是它的组成之一。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	/**
	 * Environment property that can be used to override when auto-configuration is
	 * enabled.
	 */
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

@AutoConfigurationPackage

@AutoConfigurationPackage注解的作用是将当前类所在的包及其子包中的所有类都注册到Spring Boot的自动配置中。这样,Spring Boot就可以扫描到这些类,并根据它们的特性和需求进行自动配置。

@Import(AutoConfigurationImportSelector.class)

@Import(AutoConfigurationImportSelector.class)注解的作用是让Spring Boot自动扫描classpath下的META-INF/spring.factories文件,从中获取所有的自动配置类,并将这些自动配置类导入到Spring Boot应用程序中。

spring.factories是一个标准的Java properties文件,它可以在classpath下的任何SpringFramework的jar包中找到。在这个文件中,可以通过键值对的方式指定自动配置类的全限定类名,例如:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

这个键值对指定了两个自动配置类:DataSourceAutoConfiguration和HibernateJpaAutoConfiguration。在Spring Boot启动应用程序时,Spring Boot会自动扫描到这些自动配置类,并根据它们的特性和需求进行自动配置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/742662.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nerf论文阅读笔记Neuralangelo: High-Fidelity Neural Surface Reconstruction

Neuralangelo&#xff1a;高保真神经表面重建 公众号&#xff1a;AI知识物语&#xff1b;B站暂定&#xff1b;知乎同名 视频入门介绍可以参考 B站——CVPR 2023最新工作&#xff01;Neuralangelo&#xff1a;高保真Nerf表面重建 https://www.bilibili.com/video/BV1Ju411W7…

杨氏矩阵,字符串左旋,字符串旋转结果题目解析

杨氏矩阵 题目要求:有一个数字矩阵&#xff0c;矩阵的每行从左到右是递增的&#xff0c;矩阵从上到下是递增的&#xff0c;请编写程序在这样的矩阵中查找某个数字是否存在。 示例 分析:我们仔细分析&#xff0c;不难发现&#xff0c;对于杨氏矩阵老说&#xff0c;右上角和左下…

leetcode1020. 飞地的数量

https://leetcode.cn/classic/problems/number-of-enclaves/description/ 给你一个大小为 m x n 的二进制矩阵 grid &#xff0c;其中 0 表示一个海洋单元格、1 表示一个陆地单元格。 一次 移动 是指从一个陆地单元格走到另一个相邻&#xff08;上、下、左、右&#xff09;的…

哈希的应用->位图

ps&#xff1a;左移位并不是向左移动位&#xff0c;而是低数据位向高数据位挪动 位图&#xff08;主要接口&#xff0c;set(size_t)标识、reset(size_t)取消、test(size_t) 查看 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一…

做软件测试到底要不要学编程?

乔布斯曾经说过“每个人都应该学习编程&#xff0c;因为它会教你如何思考”&#xff0c;看&#xff0c;乔帮主都觉得所有人都应该学编程&#xff0c;那你说做测试的要不要学&#xff1f;当然要。 作为测试人员&#xff0c;除了上面这个原因&#xff0c;我觉得如果会编程&#x…

Android架构之MVC,MVP,MVVM解析

MVC架构 View&#xff1a;Acitivity(View)、Fragment(View)视图&#xff0c;在android里xml布局转成View后&#xff0c;加载到了Activity/Fragment里了。 Controller&#xff1a;Controller对应着Activity/Fragment&#xff0c;绑定UI&#xff0c;处理各种业务。 Model&#xf…

python接口自动化(三十)--html测试报告通过邮件发出去——中(详解)

简介 上一篇&#xff0c;我们虽然已经将生成的最新的测试报告发出去了&#xff0c;但是MIMEText 只能发送正文&#xff0c;无法带附件&#xff0c;因此我还需要继续改造我们的代码&#xff0c;实现可以发送带有附件的邮件。发送带附件的需要导入另外一个模块 MIMEMultipart。还…

java版电子招标采购系统源码之电子招标采购实践与展望-招标采购管理系统

统一供应商门户 便捷动态、呈现丰富 供应商门户具备内外协同的能力&#xff0c;为外部供应商集中推送展示与其相关的所有采购业务信息&#xff08;历史合作、考察整改&#xff0c;绩效评价等&#xff09;&#xff0c;支持供应商信息的自助维护&#xff0c;实时风险自动提示。…

springboot+MySQL实现4S店车辆管理系统

本系统为了数据库结构的灵活性所以打算采用MySQL来设计数据库&#xff0c;而java技术&#xff0c;B/S架构则保证了较高的平台适应性。本文主要介绍了本系统的开发背景&#xff0c;所要完成的功能和开发的过程&#xff0c;主要说明了系统设计的重点、设计思想。

计算机体系结构基础知识介绍之使用多问题和静态调度来利用 流水线

为了提高处理器的性能&#xff0c;我们需要让每个时钟周期内发出多条指令&#xff0c;而不是只发出一条。这种多发射处理器有三种主要类型&#xff1a; 1. 静态调度的超标量处理器 2. VLIW&#xff08;非常长指令字&#xff09;处理器 3. 动态调度的超标量处理器。 这三种类型的…

lua 请求ftp服务器数据,下载文件

1、装入ftp库 2、调用ftp的get()方法 3、get()方法参数格式&#xff1a; 4、将返回到的数据写入文件中 例如&#xff0c;本次获取专利数据系统 http://patdata1.cnipa.gov.cn/ 的ftp站点数据 local ftp require("socket.ftp")--此处我没填端口号 file,err ftp.g…

findfont: Font family ‘Times New Roman‘ not found.

问题 Linux 使用 matplotlib.pyplot 画图时为了使字体和英文论文中的 Times of Roman 一致&#xff0c;通常会用到如下文本格式 font1 {family: Times New Roman, # x and y labelsweight: normal,size: 16}但在实际使用时会出现如下报警信息&#xff1a; findfont: Font …

element ui 导入模块的封装

导入组件的封装 <template><Modal :visible"visible" title"导入" onSave"onSave" onCancal"closeDialog"><template #default><el-upload ref"upload" class"upload-demo"action"ht…

Scala中使用 break 和 continue

Scala中没有 break 和 continue 关键字&#xff0c;但是我们可以用 Breaks 类提供的相应方法来实现对应功能。 在Java中&#xff0c;break continue return的区别 1、break&#xff1a;break不仅可以结束其所在的循环&#xff0c;还可结束其外层循环&#xff0c;但一次只能结束…

Vulnhub: Hackable:II靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.142 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.142 网站的files目录 ftp存在匿名登录&#xff0c;所在目录为网站的files目录 ftp上传反弹shell 提权 目标根目录下的.ru…

预付费智能水表远程控制系统

预付费智能水表远程控制系统是一种基于物联网技术的智能水表管理系统&#xff0c;它通过远程通信技术和云计算平台&#xff0c;实现了对水表的实时监控、数据采集、费用计算、远程控制等功能。该系统不仅可以提高水务公司的管理效率&#xff0c;还可以为用户提供更加便捷、可靠…

[疑难杂症2023-004]停止服务器自动启动的服务,解决端口占用的问题

本文由Markdown语法编辑器编辑完成。 1. 背景 前段时间&#xff0c;在linux上启动一个目录下的docker-compose.yml中的服务时&#xff0c;遇到了一个3000端口被占用的问题. 凭借经验&#xff0c;一般可能是之前的服务没被正常的停止掉&#xff0c;导致该服务占用的端口未被释…

阿里云——网站建设:动态网站建设(知识点)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 写在前面 课程目标 一.简单搭建动态网站 1.网站搭建类型 &#xff08;1&#xff0…

eclipse4.2.1 juno install SWT 1.7

SWT-windowbuilder-1.7-eclipse4.2.1-juno windows WB_v1.7.0_UpdateSite_for_Eclipse4.2.zip

【ESP32-CAM】20元就能搭建简易Web摄像头

图文步骤 在首选项中&#xff0c;增加网址https://dl.espressif.com/dl/package_esp32_index.json 安装esp32资源包 选择ESP32-CAM开发板 选一个USB-TTL的串口工具&#xff0c;按照图示&#xff0c;RX接U0TXD&#xff0c;TX接U0RXD&#xff0c;GND和5V供电&#xff0c;其中G…