# leslie-springboot-2024 **Repository Path**: leslie43/leslie-springboot-2024 ## Basic Information - **Project Name**: leslie-springboot-2024 - **Description**: Springboot学习之旅 🎉 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-11-01 - **Last Updated**: 2025-11-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringBoot ## README # Learning Path ## ------- Chapter - 1 ------- ### Springboot 入门 - 创建 Maven 工程 - 导入 `spring-boot-starter-web` 起步依赖 - 编写 controller - 提供启动类 ### 启动类 - @SpringBootApplication - 注解的意思是标记 SpringBoot应用程序的启动类 - main 方法中有一行固定的代码 `SpringApplication.run(leslieSpringBootApplication.class);` - 启动 main 方法后会自动把 `@RequestController`这样的`controller`也启动 ### Version - Springboot 3.2以上需要 Java 17 ## ------- Chapter - 2 ------- ### 学习路径 - 配置文件 - 整合 `MyBatis` - `Bean` 管理 - 自动配置原理 - 自定义 `starter` ### 配置文件 - properties (application.properties) - yaml(application.yml) 更常用 => 层级更加清晰 + 更关注数据 ### yaml 配置信息书写与获取 1. 三方技术配置新 2. 自定义配置信息 ### 配置信息的设置 - 注解 `@Autowired` 表示依赖注入, 允许 Spring 解析并注入所依赖的 Bean 到 Bean 中 - Spring 框架支持自动依赖注入, 启用 @Autowired 注解 ### 配置信息的获取 @Value 注解 - 注解 `@Value` 获取 配置文件的信息 `@Value("${keyname}")` ### 配置信息的获取 @ConfigurationProperties(prefix = ${name}) - 简化 @Value 的使用 ```yaml email: user: 111 host: 222 code: 333 ``` ### 整合 mybatis - User.java - user.sql ### @Service - 将当前类的对象交给Ioc容器 ## ------- Chapter - 3 ------- ### Bean 管理 - Bean扫描 - Bean注册 - 注册条件 ### 什么Bean - 在 Spring Boot 中,Bean是一个非常重要的概念。简单来说,Bean是由 Spring 容器(如ApplicationContext)所管理的对象。这些对象是按照 Spring 的配置(可以是基于 Java 配置类、XML 配置文件等方式)创建和管理的。例如,在一个简单的 Web 应用程序中,UserService对象可以被定义为一个Bean,由 Spring 容器来负责它的生命周期管理。 ### Bean的作用 - `依赖注入`: Bean是实现依赖注入(Dependency Injection,DI)的核心。依赖注入是一种设计模式,它允许对象通过构造函数、setter 方法或其他方式接收其所依赖的其他对象,而不是在对象内部直接创建这些依赖。例如,一个UserController可能依赖于一个UserService来处理业务逻辑。在 Spring Boot 中,可以将UserService定义为一个Bean,然后通过依赖注入的方式将其注入到UserController中。 - 比如 ```java @Service public class UserService { // 业务逻辑方法 public User getUserById(Long id) { // 从数据库获取用户的逻辑 return user; } } @RestController public class UserController { private final UserService userService; @Autowired public UserController(UserService userService) { this.userService = userService; } @GetMapping("/user/{id}") public User getUser(@PathVariable Long id) { return userService.getUserById(id); } } ``` - 在这个例子中,UserService是一个Bean(通过@Service注解定义),UserController通过构造函数注入的方式接收UserService这个Bean,从而实现了依赖注入。这样的好处是可以降低代码的耦合度,方便进行单元测试和代码维护。 ### 生命周期管理 - Spring 容器负责Bean的创建、初始化、销毁等生命周期阶段。例如,在Bean创建时,Spring 可以执行一些初始化操作,如设置默认属性值、加载配置文件等。在Bean销毁时,也可以进行资源清理工作,如关闭数据库连接、释放文件资源等。 - 可以通过实现InitializingBean和DisposableBean接口来定义Bean的初始化和销毁方法 ```java import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; @Component public class MyBean implements InitializingBean, DisposableBean { @Override public void afterInitialization() { // 初始化方法,在Bean创建后执行 System.out.println("MyBean is initialized"); } @Override public void destroy() { // 销毁方法,在Bean销毁时执行 System.out.println("MyBean is destroyed"); } } ``` - 另外,也可以使用@PostConstruct和@PreDestroy注解来达到类似的效果,这两种注解更加方便和灵活。例如 ```java import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.stereotype.Component; @Component public class MyBean { @PostConstruct public void init() { System.out.println("MyBean is initialized"); } @PreDestroy public void cleanUp() { System.out.println("MyBean is destroyed"); } } ``` ### Bean的创建方式 - 基于注解的方式 - Spring Boot 提供了多种注解来定义Bean。例如,@Component是一个通用的注解,用于将一个普通的 Java 类标记为一个Bean。当 Spring 扫描到带有@Component注解的类时,会将其纳入容器管理范围并创建相应的Bean。 - 除了@Component,还有一些更具语义的注解,如@Service(用于标记服务层的类)、@Repository(用于标记数据访问层的类)、@Controller(用于标记控制层的类,在 Web 应用中用于处理请求)等。这些注解本质上都是@Component的衍生,只是为了更好地划分不同层次的Bean。 - 例如,以下是一个使用@Service注解定义Bean的示例 ```java @Service public class UserService { // 业务逻辑方法 } ``` ### Bean的创建方式 - 基于 Java 配置类的方式 - 可以通过创建一个 Java 配置类,在类中使用@Bean注解来定义Bean。这种方式更加灵活,可以在方法中进行复杂的对象创建和初始化逻辑。 ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public MyObject myObject() { MyObject myObject = new MyObject(); myObject.setProperty("value"); return myObject; } } ``` - 在这个例子中,AppConfig是一个配置类(通过@Configuration注解标记),myObject方法返回一个MyObject类型的Bean。Spring 容器会在启动时调用这个方法来创建Bean,并且可以根据方法的返回值进行依赖注入等操作。 ### Bean的创建方式 - 基于 XML 配置文件的方式(较少使用) - 虽然在现代 Spring Boot 应用中,基于 XML 配置文件的方式已经不那么常见,但在一些遗留系统或者需要与其他框架集成的场景下可能会用到。在 XML 配置文件中,可以使用标签来定义Bean,包括指定Bean的类名、属性值、初始化方法和销毁方法等信息。 ```xml ``` - 在这个 XML 配置文件中,定义了一个id为myObject,类为com.example.MyObject的Bean,并且设置了一个属性property的值为value。 ### Bean 扫描 - Springboot 只所以能自动扫描到 Controller, Service, 其核心就在于`@SpringBootApplication`这个注解上 - `@SpringBootApplication`这个注解是一个组合注解包含一下内容 - - `@SpringBootConfigruation` - - `@EnableAutoConfiguration` - - `@ComponentScan` #### `@ComponentScan`并没有指定扫描路径,为什么依然能扫描到`Controller`和`Services`? - 如果不指定路径,则扫描添加此注解的类的包及其子包 - 可以手动指定指定的目录`@ComponentScan("com.xxxxx")` ### Bean 注册 - 如果要注册的bean对象来自于第三方(不是自定义的),是无法使用 @Component及衍生注解声明bean的. - `@Bean` 不推荐,建议使用 Config 的方式 ```java @Configuration public class CommonConfig { @Bean public Country country() { return new Country(); } // 对象默认的名字是方法铭 // @Bean("aaa") // 如果方法的内部需要使用ioc容器中已经存在的Bean对象, 那么只需要在方法上声明即可, spring会自动引入 @Bean public Province province(Country country) { System.out.println(country); return new Province(); } } ``` ### 通过 @Import({CommonConfig.class}) - `@Import({CommonConfig.class})` // 手动扫描Configuration,支持多个 ### 通过 @ImportSelector - 参见 `config/CommonImportSelector.java` ### Bean 的注册条件 - `@ConditionalOnProperty`: 配置文件中有对应的属性,才声明该Bean ```java @ConditionalOnProperty(prefix = "country", name = {"name","system"}) @Bean public Country country(@Value("${country.name}") String name,@Value("${country.system}") String system) { Country country = new Country(); country.setName(name); country.setSystem(system); return country; } ``` - `@ConditionalOnMissingBean`: ConditionalOnMissingBean: 如果Ioc容器中不存在 Country 则注入Province, 否则不注入 ```java @ConditionalOnMissingBean(Country.class) public Province province() { return new Province(); } ``` - `@ConditionalOnClass(name="org.springframework.web.servlet.DispatcherServlet")`:当前环境存在指定的类时才声明该Bean - 如果当前环境中有 DispatcherServlet 类, 则注入 Province, 否则不注入 - 如果当前环境中引入了 web 起步依赖, 则环境中有 DispatcherServlet,否则没有 ```java @Bean @ConditionalOnClass(name="org.springframework.web.servlet.DispatcherServlet") public Province province() { return new Province(); } ``` ## FAQ: IoC: Inversion of Control 控制反转 ### IoC 概念 - 传统的应用程序中,对象的创建和依赖关系的管理通常由程序自身来控制。而在使用 IoC 的应用中,对象的创建和依赖关系的管理被转移到了容器中,由容器来负责对象的创建、配置和组装,这就是 “控制反转”。 ### Spring Boot 中的 IoC 容器具体表现 - #### 对象的创建 - - 当一个 Spring Boot 应用启动时,IoC 容器会根据配置(通常是通过注解或 XML 配置文件)自动创建应用中所需的各种对象。例如,使用 @Component、@Service、@Repository、@Controller 等注解标记的类,容器会自动实例化这些类的对象。 - - 容器在创建对象时可以根据需要进行一些额外的处理,比如设置对象的属性、调用对象的初始化方法等。 -. 依赖注入 - - 如果一个对象 A 需要依赖另一个对象 B,在传统方式下,对象 A 可能需要自己负责创建对象 B。但在 Spring Boot 的 IoC 容器中,容器会自动将对象 B 注入到对象 A 中。这可以通过构造函数注入、属性注入或方法注入等方式实现。 - - 例如,使用 @Autowired 注解可以自动注入依赖的对象。如果有多个实现类,可以结合 @Qualifier 注解指定具体要注入的实现。 - #### 管理对象的生命周期 - - IoC 容器还负责管理对象的生命周期。它可以决定对象何时被创建、何时被销毁以及在不同的作用域(如 singleton、prototype 等)下的行为。 - - 例如,默认情况下,使用 @Component 等注解标记的对象是单例的,即整个应用中只有一个实例。但可以通过配置改变对象的作用域。 - #### 配置管理 - - IoC 容器允许通过外部配置文件(如 application.properties 或 application.yml)来配置对象的属性和行为。容器在创建对象时会读取这些配置信息,并将其应用到对象上。 - 可以使用 @Value 注解将配置文件中的值注入到对象的属性中。 - #### IoC容器的好处 - - 解耦:通过将对象的创建和依赖关系的管理交给容器,各个组件之间的耦合度降低。组件只需要关注自己的业务逻辑,而不需要关心依赖对象的创建和管理。 - - 可测试性提高:在测试时,可以方便地替换依赖的对象,进行单元测试和集成测试。 - - 代码的可维护性和可扩展性增强:当需要修改对象的创建方式或依赖关系时,只需要在容器的配置中进行修改,而不需要在多个地方修改代码。 ## FAQ: List 和 ArrayList 的关系 - 在 Java 中,ArrayList是List接口的一个实现类。 - List `接口` - - List是 Java 集合框架中的一个接口,它继承自Collection接口。 - - List接口定义了一组操作线性列表的方法,主要特点包括 - ArrayList: `实现类` - - ArrayList实现了List接口,以数组的方式实现了线性列表的数据结构。 - - ArrayList的主要特点包括: 1. 动态增长:当需要添加更多元素而现有容量不足时,ArrayList会自动增加其内部数组的大小。 2. 随机访问:可以通过索引快速访问元素,时间复杂度为 O (1)。 3. 插入和删除操作:在中间位置插入或删除元素时,时间复杂度为 O (n),因为需要移动后续元素。 - 接口与实现类的关系:ArrayList实现了List接口中定义的所有方法,同时还可以根据自身的实现特点提供一些额外的方法。 - 多态性:可以使用List接口类型的变量来引用ArrayList对象,这样在需要更换具体的列表实现时,只需要修改创建对象的代码,而使用列表的代码无需修改 ## Springboot 自动配置原理 ### SpringBootApplication - 是一个组合注解, `@SpringbootConfiguration` 和 `@EnableAutoConfiguration` - `@EnableAutoConfiguration` 也是一个组合注解, 重写了selectImports方法 ### DispatcherServletConfiguration - `@AutoConfiguration` 和 `@ConditionalOnClass` 注解 - 当引入了 web 起步依赖后就会注册 `DispatcherServlet` ### 自动配置的核心要点 - autoconfig.AutoConfiguration.imports 文件是重点 - Springboot 2.7以前的文件是 spring.factory, 2.7以后兼容 `factory`和`imports`文件 - 自动配置无非就是提供一个自动配置类,把这个类名写到自动配置文件里就行了 - 自动配置类 ```java import config.CommonConfig; import org.springframework.boot.autoconfigure.AutoConfiguration; @AutoConfiguration @Import({CommonConfig.class}) public class CommonAutoConfig(){ public CommonAutoConfig(){} } ``` ## FAQ: Springboot自动配置原理 - 在主启动类上添加了`SpringBootApplication`注解, 这个注解组合了`EnableAutConfiguration`注解 - `EnableAutConfiguration`注解 也是一个组合注解, 它又组合了`Import`注解, 导入了 `AutoConfigruationImportSelector`类 - `AutoConfigruationImportSelector`类 实现了 `selectImports`方法, 这个方法经过层层调用最终会读取`META-INFO`目录下的后缀名为`imports`的文件, `springboot2.7`以前是读取`factory`文件 - 在`imports`文件里会配置很多全类名并解析注册条件, 也就是`@Conditional`及其衍生注解, 把满足注册条件的`Bean`对象自动注入到IoC容器中去 ### 自定义starter - 自定义一般由两个文件组成 `xxx.xxx.xxx-autoconfigure:mm:nn:zz`(自动配置功能-Function) 和 `xxx.xxx.xxx-starter:mm:nn:zz`(依赖管理功能-Expose) - Step1: `创建xxx.autoconfig`模块, 提供自动配置功能《 并定义配置文件`META-INF/spring/xx.imports` - Step2: `创建xxx.starter`模块, 在starter中引入自动配置模块 - 扫描指定注解的 方法`mapperScannerConfigurer.setAnnotationClass(Mapper.class)` - 提供META-INF, `/resource/META-INF/spring/xxxx.xxxx.xxx.xxxx.AutoConfiguration` - starter只负责管理包的版本依赖 - 设定 build JDK 版本 ```xml org.apache.maven.plugins maven-compiler-plugin 3.11.1 17 17 ```