From da19dd00ca8046df403ceba11510a1fab899438b Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Wed, 26 Nov 2025 19:55:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=9B=B4=E6=96=B0=E5=8D=9A=E5=AE=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/vcs.xml | 6 + Dockerfile | 5 + docs/.vitepress/config.mts | 55 ++- docs/DevOps/ElasticSearch部署和使用.md | 82 ++++ docs/DevOps/index.md | 1 + docs/SpringBoot/SpringBoot启动流程.md | 281 +++++++++++++ docs/SpringBoot/SpringIOC简介.md | 543 +++++++++++++++++++++++++ docs/SpringBoot/index.md | 9 + nginx.conf | 18 + package.json | 2 +- 10 files changed, 979 insertions(+), 23 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 Dockerfile create mode 100644 docs/DevOps/ElasticSearch部署和使用.md create mode 100644 docs/SpringBoot/SpringBoot启动流程.md create mode 100644 docs/SpringBoot/SpringIOC简介.md create mode 100644 docs/SpringBoot/index.md create mode 100644 nginx.conf diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c83b177 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM nginx:1.27.0 +COPY docs/.vitepress/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN echo 'Asia/Shanghai' > /etc/timezone diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index d270810..54041c0 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -2,23 +2,28 @@ import { defineConfig } from 'vitepress' // https://vitepress.dev/reference/site-config export default defineConfig({ - lang: 'zh-CN', title: "Cxx0822", description: "Cxx0822 Blog", base: '/blog-press/', + lang: 'zh-CN', + locales: { + "/": { + label: "简体中文", + lang: "zh-CN", + }, + }, themeConfig: { // https://vitepress.dev/reference/default-theme-config nav: [ { text: 'Home', link: '/' }, { text: 'Web', link: '/Web/' }, - { text: 'DevOps', link: '/DevOps/' } + { text: 'DevOps', link: '/DevOps/' }, + { text: 'SpringBoot', link: '/SpringBoot/' } ], - sidebar: { '/Web/': [ { text: 'Web', - collapsible: true, items: [ { text: 'MySQL知识点', link: '/Web/MySQL知识点' } ] @@ -27,13 +32,22 @@ export default defineConfig({ '/DevOps/': [ { text: 'DevOps', - collapsible: true, items: [ { text: 'OpenObserve部署和简单使用', link: '/DevOps/OpenObserve部署和简单使用' }, - { text: 'Jenkins部署和使用', link: '/DevOps/Jenkins部署和使用' } + { text: 'Jenkins部署和使用', link: '/DevOps/Jenkins部署和使用' }, + { text: 'ElasticSearch部署和使用', link: '/DevOps/ElasticSearch部署和使用' } ] } ], + '/SpringBoot/': [ + { + text: 'SpringBoot', + items: [ + { text: 'Spring IOC简介', link: '/SpringBoot/SpringIOC简介' }, + { text: 'SpringBoot启动流程', link: '/SpringBoot/SpringBoot启动流程' } + ] + } + ] }, // socialLinks: [ @@ -45,14 +59,6 @@ export default defineConfig({ copyright: 'Copyright © 2025 Cxx0822' }, - lastUpdated: { - text: '最后更新于', - formatOptions: { - dateStyle: 'full', - timeStyle: 'medium' - } - }, - search: { provider: 'local', options: { @@ -74,18 +80,23 @@ export default defineConfig({ } }, - // 返回顶部按钮配置 - returnToTop: { - // 显示返回顶部按钮的阈值(滚动距离) - threshold: 300, - // 按钮文本 - text: '返回顶部' + outline: { + label: "目录", + level: [1, 2] }, - + + returnToTopLabel: "返回顶部", + // 上下篇导航 docFooter: { prev: '上一篇', next: '下一篇' }, - } + + lastUpdated: { + text: '最后更新于' + } + }, + + lastUpdated: true, }) diff --git a/docs/DevOps/ElasticSearch部署和使用.md b/docs/DevOps/ElasticSearch部署和使用.md new file mode 100644 index 0000000..b52bdcc --- /dev/null +++ b/docs/DevOps/ElasticSearch部署和使用.md @@ -0,0 +1,82 @@ +## 一、基础概念 + +## 二、Docker部署 +```yml +services: + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0 + container_name: elasticsearch + environment: + - discovery.type=single-node + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + - xpack.security.enabled=true + - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} + ports: + - "9200:9200" + volumes: + - ./elasticsearch-data:/usr/share/elasticsearch/data + networks: + - devops + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "curl -sS -u elastic:${ELASTIC_PASSWORD} http://localhost:9200/_cluster/health?wait_for_status=yellow&timeout=5s || exit 1"] + interval: 10s + timeout: 10s + retries: 3 + start_period: 60s + + kibana: + image: docker.elastic.co/kibana/kibana:8.12.0 + container_name: kibana + environment: + - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 + - ELASTICSEARCH_USERNAME=kibana_system + - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD} + ports: + - "5601:5601" + networks: + - devops + restart: unless-stopped + depends_on: + elasticsearch: + condition: service_healthy + +networks: + devops: + driver: bridge + +volumes: + elasticsearch-data: + driver: local +``` + +  elasticsearch和kibana版本要保持一致,该镜像较大,可以先使用docker pull拉取到本地。 +  ELASTIC_PASSWORD和KIBANA_PASSWORD可以通过.env配置文件设置。 +  启动时,elasticsearch可能会提示elasticsearch-data文件夹权限问题,目前解决方案为将其权限设置为777。 + +## 三、简单使用 +### 3.1 安装插件 +  启动成功后,需要安装elasticsearch的分词插件analysis-ik。 +  进入Docker容器,输入指令: +```cmd +bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.12.0 +``` + +  注意版本要匹配。https://github.com/infinilabs/analysis-ik/releases/tag/Latest +  安装完成后,重启容器。 + + +### 3.2 更改密码 +  启动成功后,需要更改elasticsearch的账号密码(不知道为啥docker-compose文件设置的密码不行,可能是容器初始化后又重置了)。 +  进入Docker容器,输入指令: +```cmd +bin/elasticsearch-setup-passwords interactive +``` + +  根据提示输入相应的账号密码。 + +### 3.3 新建索引 +1. 打开Elastic控制台,选择Management->Dev Tools,输入语句新建索引。 +2. 选择Management->Stack Management->Data Views,选择Create data view新建数据视图。 +3. 输入name、index pattern(刚才新建的索引)和Timestamp信息,保存数据视图。 +4. 选择Discover,选择刚才的数据视图即可查看该视图下所有数据。 diff --git a/docs/DevOps/index.md b/docs/DevOps/index.md index 3ebc5e3..21f8d68 100644 --- a/docs/DevOps/index.md +++ b/docs/DevOps/index.md @@ -7,3 +7,4 @@ title: DevOps - [OpenObserve部署和简单使用](/DevOps/OpenObserve部署和简单使用) - [Jenkins部署和使用](/DevOps/Jenkins部署和使用) +- [ElasticSearch部署和使用](/DevOps/ElasticSearch部署和使用) diff --git a/docs/SpringBoot/SpringBoot启动流程.md b/docs/SpringBoot/SpringBoot启动流程.md new file mode 100644 index 0000000..056048f --- /dev/null +++ b/docs/SpringBoot/SpringBoot启动流程.md @@ -0,0 +1,281 @@ +# 一、启动流程 +![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/7d7b8c086729d400a3891a20f2107fa6.png 'SpringBoot启动流程.png') + +# 二、 阶段详解 +## 2.1 SpringApplication初始化 +**🔹 步骤1.1 - main方法入口执行** +- 执行位置:标注@SpringBootApplication的类中的main方法 +- 核心动作: + 1. 创建SpringApplication实例对象 + 2. 设置应用的基本配置信息 + 3. 准备启动所需的基础环境 + +  main方法是整个Spring Boot应用启动的唯一起点。当Java虚拟机开始执行程序时,首先会调用标注有@SpringBootApplication注解的主类中的main方法。在这个方法内部,会创建SpringApplication实例并调用其run方法,正式开启启动流程。 +  SpringApplication的构造方法会进行一些重要的初始化工作,包括推断主配置类、设置初始引导类等。推断主配置类的过程是通过分析当前线程的堆栈信息来完成的,确保能够准确找到包含main方法的那个类。 + +**🔹 步骤1.2 - 加载SpringFactories配置** +- 配置源:META-INF/spring.factories文件 +- 加载内容: + 1. ApplicationContextInitializer(上下文初始化器) + 2. ApplicationListener(应用监听器) + 3. BeanFactoryPostProcessor(Bean工厂后处理器) + 4. AutoConfigurationImportSelector(自动配置选择器) + +  Spring Boot使用SpringFactoriesLoader机制从类路径下的**META-INF/spring.factories**文件中加载各种扩展组件。**这种机制是Spring Boot自动配置的核心基础,它允许框架和开发者通过标准的配置文件来注册和发现各种扩展实现。** +  配置文件中定义了多种类型的组件,包括**应用上下文初始化器、应用事件监听器、Bean工厂后处理器**等。这些组件将在后续的启动过程中按照特定的顺序被执行,共同完成应用的初始化工作。 + +**🔹 步骤1.3 - 推断Web应用类型** +- 检测逻辑: + 1. 检查类路径是否存在Servlet相关类 + 2. 检查Spring MVC相关组件 + 3. 检查WebFlux相关组件 +- 推断结果 + 🅰️ SERVLET:传统Web应用 + 🅱️ REACTIVE:响应式Web应用 + ©️ NONE:非Web应用 + +  应用类型推断是Spring Boot自动配置的重要环节。系统会根据项目的依赖情况自动判断应用类型,这直接影响后续创建的应用上下文类型和内嵌服务器的选择。 +  **推断过程主要通过检查类路径中是否存在特定的类来完成。例如,如果存在Servlet相关的类,就推断为Web应用;如果存在WebFlux相关的类,就推断为响应式Web应用。** 这种基于类路径的自动推断机制使得开发者无需手动配置应用类型,大大简化了配置工作。 + +## 2.2 环境准备与配置加载 +**🔹 步骤2.1 - 创建环境对象** +``` +环境对象层次结构: +Environment(环境接口) + ↓ +ConfigurableEnvironment(可配置环境) + ↓ +具体环境实现(StandardEnvironment/StandardServletEnvironment) + ├── PropertySources(属性源列表) + ├── Profiles(激活的配置文件) + └── ConversionService(类型转换服务) +``` + +  环境对象是Spring Boot应用运行时的配置中心,它负责管理所有的配置属性和运行环境信息。根据应用类型的不同,Spring Boot会创建相应的环境实例。 +  环境对象采用分层设计,提供了统一的属性访问接口,同时支持多种属性源的动态管理。环境对象还负责管理激活的配置文件(Profile),支持基于不同环境的配置隔离和切换。 + +**🔹 步骤2.2 - 配置属性源加载** +📊 属性源加载优先级(从高到低): +| 优先级 | 属性源类型 | 说明 | +| - | - | - | +| 1 | 命令行参数 | --spring.profiles.active=dev | +| 2 | Java系统属性 | System.getProperties() | +| 3 | 操作系统环境变量 | 系统级环境配置 | +| 4 | 应用配置文件 | application-{profile}.yml/properties | +| 5 | 默认属性 | SpringApplication.setDefaultProperties() | + +  属性源加载遵循严格的优先级顺序,确保重要的配置能够覆盖默认配置。这种优先级设计使得配置管理更加灵活,开发者可以通过不同级别的配置来调整应用行为。 + +**🔹 步骤2.3 - Profile处理机制** +- Profile激活方式: + 1. 通过spring.profiles.active显式指定 + 2. 通过spring.profiles.include包含其他profile + 3. 默认使用default profile +- Profile解析流程: + 1. 读取所有可用的profile配置 + 2. 解析条件化配置注解 + 3. 合并不同profile的配置项 + 4. 处理配置覆盖和冲突解决 + +  Profile机制是Spring框架提供的环境隔离解决方案,它允许开发者为不同的运行环境定义不同的配置。Spring Boot在启动时会根据激活的Profile来加载相应的配置,并处理配置之间的覆盖关系。 +  Profile的激活可以通过多种方式实现,包括命令行参数、系统属性、配置文件等。系统支持同时激活多个Profile,并提供了灵活的配置合并策略来处理可能出现的配置冲突。 + +**🔹 步骤2.4 - 配置属性绑定** +1. 属性值解析:从各种属性源中获取属性值 +2. 类型转换:将字符串值转换为目标类型 +3. 数据验证:基于JSR-303进行数据校验 +4. 对象绑定:将属性值设置到@ConfigurationProperties类 +   配置属性绑定是将外部配置值注入到Java对象中的过程。Spring Boot提供了强大的属性绑定功能,支持宽松的绑定规则、类型转换、数据验证等特性。 +   绑定过程首先会从环境对象中获取属性值,然后进行类型转换,将字符串类型的配置值转换为目标属性类型。如果配置了验证规则,还会执行数据验证,确保配置值的正确性。最后,将验证通过的属性值设置到目标对象中。 + +## 2.3 应用上下文创建与初始化 +**🔹 步骤3.1 - 创建应用上下文实例** +📋 上下文类型映射表: +| 应用类型 | 上下文实现类 | 特点描述 | +| - | - | - | +| Web应用 | AnnotationConfigServletWebServerApplicationContext | 支持Servlet容器 | +| 响应式应用 | AnnotationConfigReactiveWebServerApplicationContext | 支持响应式编程 | +| 普通应用 | AnnotationConfigApplicationContext | 基础应用上下文 | + +  应用上下文是Spring框架的核心容器,负责管理Bean的生命周期和依赖关系。Spring Boot会根据应用类型创建相应类型的应用上下文实例 + +**🔹 步骤3.2 - 应用上下文层次结构** +``` +BeanFactory(Bean工厂基础接口) + ↓ +ApplicationContext(应用上下文接口) + ↓ +ConfigurableApplicationContext(可配置应用上下文) + ↓ +AbstractApplicationContext(抽象实现) + ↓ +GenericApplicationContext/AnnotationConfigApplicationContext +``` + +  应用上下文采用层次化设计,不同层次的接口和类承担不同的职责。这种设计使得上下文的功能可以逐步扩展,同时保持代码的清晰性和可维护性。 + +**🔹 步骤3.3 - 执行应用上下文初始化器** +- 执行时机:上下文创建后,Bean加载前 +- 主要功能: + 1. 🔧 注册自定义Bean定义 + 2. 🔧 设置上下文特定属性 + 3. 🔧 添加特殊的后处理器 + 4. 🔧 配置环境变量覆盖 + +  应用上下文初始化器是Spring Boot提供的重要扩展点,允许开发者**在上下文正式刷新之前执行自定义的初始化逻辑。** **初始化器可以通过spring.factories文件注册,也可以通过SpringApplication的addInitializers方法添加。** +  **初始化器的主要作用包括注册自定义的Bean定义、配置上下文特定的属性、添加特殊的后处理器等。** 通过初始化器,开发者可以深度定制应用上下文的行为,满足特殊的业务需求。 + +**🔹 步骤3.4 - 发布应用上下文事件** +事件发布序列: +1. ApplicationStartingEvent- 应用启动事件 +2. ApplicationEnvironmentPreparedEvent- 环境准备完成事件 +3. ApplicationContextInitializedEvent- 上下文初始化事件 +4. ApplicationPreparedEvent- 应用准备事件 + +  Spring Boot的启动过程采用事件驱动模型,**每个关键步骤都会发布相应的事件**。这种设计使得各个模块之间解耦,同时也便于开发者通过监听事件来扩展启动逻辑。 + +## 2.4 Bean定义加载与处理 +**🔹 步骤4.1 - Bean定义加载方式** +多种Bean定义加载途径: +1. 🔍 组件扫描:自动扫描@Component、@Service等注解 +2. 📝 @Bean方法:处理@Configuration类中的@Bean方法 +3. 📂 @Import导入:导入其他配置类 +4. 🔗 ImportSelector:动态选择导入的配置类 + +  Bean定义加载是Spring容器初始化的核心环节。Spring Boot支持多种Bean定义加载方式,每种方式都有其适用的场景和特点。 + +**🔹 步骤4.2 - 组件扫描详细过程** +``` +组件扫描流程: +开始扫描指定包路径 + ↓ +读取包下的所有class文件 + ↓ +解析类上的注解信息 + ↓ +识别Spring组件注解 + ↓ +注册Bean定义到容器 + ↓ +完成组件扫描 +``` + +  组件扫描是Spring Boot自动配置的基础机制,它能够自动发现和注册项目中的Spring组件。扫描过程基于注解元数据,通过反射机制分析类的结构信息。 + +**🔹 步骤4.3 - Bean工厂后处理** +| 后处理器 | 功能描述 | 执行时机 | +| - | - | - | +| ConfigurationClassPostProcessor | 处理@Configuration类 | Bean定义加载后 | +| PropertySourcesPlaceholderConfigurer | 处理属性占位符 | 属性解析阶段 | +| CustomScopeConfigurer | 注册自定义作用域 | 作用域配置阶段 | + +  BeanFactoryPostProcessor是Spring框架的重要扩展点,允许在Bean实例化之前修改Bean定义信息。Spring Boot在启动过程中会执行多个内置的BeanFactoryPostProcessor。 + +## 2.5 Bean实例化与生命周期 +**🔹 步骤5.1 - Bean实例化策略** +实例化顺序规则: +1. 🥇 BeanFactoryPostProcessor- 工厂后处理器最先实例化 +2. 🥈 BeanPostProcessor- Bean后处理器其次实例化 +3. 🥉 单例Bean- 按依赖顺序实例化普通Bean +4. 🏅 其他作用域Bean- 按需实例化 + +  Bean实例化遵循特定的顺序规则,确保依赖关系正确的Bean能够按正确的顺序创建。实例化过程采用懒加载和急切实例化相结合的策略。 + +**🔹 步骤5.2 - 依赖注入机制** +依赖注入的三种方式: +1. 🏗️ 构造器注入- 通过构造函数注入依赖 +2. 🛠️ Setter注入- 通过setter方法注入依赖 +3. 🎯 字段注入- 直接在字段上使用@Autowired注入 + +  依赖注入是Spring框架的核心特性,它通过自动装配机制将Bean之间的依赖关系解耦。Spring支持多种依赖注入方式,每种方式都有其适用的场景。 + +**🔹 步骤5.3 - Bean后处理流程** +``` +Bean后处理序列: +Bean实例化 + ↓ +执行BeanPostProcessor.postProcessBeforeInitialization + ↓ +执行@PostConstruct方法 + ↓ +执行InitializingBean.afterPropertiesSet + ↓ +执行自定义init方法 + ↓ +执行BeanPostProcessor.postProcessAfterInitialization + ↓ +Bean完全就绪 +``` + +  BeanPostProcessor是Bean生命周期管理的重要扩展点,它允许在Bean初始化前后执行自定义逻辑。Spring Boot内置了多个BeanPostProcessor,用于处理各种注解和AOP代理。 + +**🔹 步骤5.4 - 循环依赖解决机制** +三级缓存解决方案: +1. 一级缓存:存放完全初始化完成的Bean +2. 二级缓存:存放早期暴露的Bean(已实例化但未初始化) +3. 三级缓存:存放Bean工厂,用于创建Bean的早期引用 + +  循环依赖是Spring容器需要解决的重要问题。Spring通过三级缓存机制来解决单例Bean的循环依赖问题,确保即使存在循环引用也能正确完成依赖注入。 + +## 2.6 Web服务器启动与配置 +**🔹 步骤6.1 - 内嵌服务器选择策略** +服务器自动配置逻辑: +1. 检查类路径中的服务器依赖 +2. 按优先级选择:Tomcat > Jetty > Undertow +3. 根据应用类型创建对应的Web服务器工厂 +4. 配置服务器参数(端口、上下文路径等) + +  Spring Boot支持多种内嵌服务器,包括Tomcat、Jetty和Undertow。服务器选择基于类路径中的依赖,采用特定的优先级规则。 + +**🔹 步骤6.2 - Servlet容器初始化** +1. 🎯 创建ServletContext(Servlet上下文) +2. 🎯 注册DispatcherServlet(前端控制器) +3. 🎯 配置字符编码过滤器 +4. 🎯 设置会话管理配置 +5. 🎯 启用静态资源服务 + +  Servlet容器初始化是Web应用启动的关键环节。Spring Boot会自动配置Servlet容器,并注册必要的Servlet、Filter和Listener。 + +**🔹 步骤6.3 - MVC组件自动配置** +自动配置的MVC组件: +1. HandlerMapping- 请求映射处理器 +2. HandlerAdapter- 处理器适配器 +3. ViewResolver- 视图解析器 +4. MessageConverter- 消息转换器 +5. Interceptor- 拦截器配置 + +  Spring Boot为Spring MVC提供了完整的自动配置,包括处理器映射、视图解析、消息转换等组件。这些组件基于约定大于配置的原则,提供了合理的默认值。 + +## 2.7 启动完成与后处理 +**🔹 步骤7.1 - 启动事件发布序列** +``` +ApplicationStartingEvent + ↓ +ApplicationEnvironmentPreparedEvent + ↓ +ApplicationContextInitializedEvent + ↓ +ApplicationPreparedEvent + ↓ +ContextRefreshedEvent + ↓ +ApplicationReadyEvent +``` + +  当所有的Bean实例化、依赖注入和初始化回调都执行完成后,Spring容器会发布ContextRefreshedEvent事件。这个事件标志着Spring IoC容器已经完全刷新并准备就绪。 + +**🔹 步骤7.2 - 命令行运行器执行** +运行器类型与特点: +| 运行器接口 | 执行方法 | 参数类型 | 使用场景 | +| - | - | - | - | +| ApplicationRunner | run(ApplicationArguments) | 封装的应用参数 | 需要丰富参数信息时 | +| CommandLineRunner | run(String... args) | 原始字符串参数 | 简单参数处理时 | + +  Spring Boot会执行所有实现了ApplicationRunner或CommandLineRunner接口的Bean。 + +**🔹 步骤7.3 - 健康检查与指标收集** +启动后的监控机制: +1. ❤️ 健康检查:通过HealthIndicator监控应用健康状态 +2. 📊 应用指标:通过Micrometer收集运行时指标 +3. 🔔 事件监听:监控应用生命周期事件 +4. 📝 日志记录:记录启动完成状态和耗时 diff --git a/docs/SpringBoot/SpringIOC简介.md b/docs/SpringBoot/SpringIOC简介.md new file mode 100644 index 0000000..2b7b6d3 --- /dev/null +++ b/docs/SpringBoot/SpringIOC简介.md @@ -0,0 +1,543 @@ +# 一、IOC +  Spring框架的核心是IOC(控制反转)容器,它负责管理应用程序中的对象(称为Bean)的创建、配置和组装。 + +# 二、Bean +## 2.1 定义 +  在Spring中,Bean是指由Spring IOC容器管理的对象实例。这些对象不再由应用程序直接创建,而是由容器负责实例化、配置和组装。 +  例如@Service、@Controller就是特殊的Bean。 + +## 2.2 特点 +- 由容器管理:生命周期由Spring容器控制 +- 可配置性:通过配置元数据定义Bean的行为 +- 依赖注入:容器自动处理Bean之间的依赖关系 +- 作用域支持:支持singleton、prototype等不同作用域 + +## 2.3 创建方式 +```java +// 1. 通过@Component注解 +@Component +public class UserService { + // ... +} + +// 2. 通过@Bean注解(配置类中) +@Configuration +public class AppConfig { + @Bean + public DataSource dataSource() { + return new DataSource(); + } +} + +// 3. 通过XML配置 + +``` + +## 2.4 作用域 +  控制 Bean 在容器中的实例数量和生命周期。Spring 提供多种作用域,默认是 singleton。通过 @Scope 注解指定,如 @Scope("prototype")。 +- singleton(单例):容器中只有一个实例,所有请求共享该实例(默认值)。 +- prototype(多例):每次请求(如 getBean())都会创建新实例,容器不管理其销毁。 +- request(Web):每个 HTTP 请求创建一个实例,仅在当前请求有效。 +- session(Web):每个会话创建一个实例,在会话有效期内有效。 + +## 2.5 生命周期 +1. 实例化(Instantiation):容器通过构造器创建 Bean 实例(分配内存)。 +2. 属性注入(Population):容器将依赖的 Bean 注入到当前 Bean 的字段或方法(如 @Autowired 标注的依赖)。 +3. 初始化前(Post-processing before initialization): + 执行 BeanPostProcessor 的 postProcessBeforeInitialization 方法(AOP 代理生成在此阶段)。 +4. 初始化(Initialization): + 调用 @PostConstruct 注解的方法(JSR-250 标准,推荐)。 + 若实现 InitializingBean 接口,调用 afterPropertiesSet() 方法。 + 执行自定义初始化方法(如 @Bean(initMethod = "init") 中指定的 init 方法)。 +5. 初始化后(Post-processing after initialization): + 执行 BeanPostProcessor 的 postProcessAfterInitialization 方法。 +6. 使用(In Use):Bean 被应用程序调用。 +7. 销毁(Destruction): + 调用 @PreDestroy 注解的方法(JSR-250 标准,推荐)。 + 若实现 DisposableBean 接口,调用 destroy() 方法。 + 执行自定义销毁方法(如 @Bean(destroyMethod = "destroy") 中指定的 destroy 方法)。 + +![暂无图片](https://cxx0822.iepose.cn/rustfs/blog/b1054386c885ffefb0f08074ad6b6268.png 'Bean生命周期.png') + + +# 三、BeanDefinition +## 3.1 定义 +  BeanDefinition是Spring框架中描述Bean的元数据对象,它包含了创建Bean实例所需的所有信息。 + +## 3.2 作用 +- 定义Bean的类名 +- 设置Bean的作用域 +- 配置Bean的属性值 +- 定义依赖关系 +- 配置初始化/销毁方法 + +## 3.3 结构 +```xml +BeanDefinition (接口) + ↑ +AbstractBeanDefinition (抽象类) + ↑ +RootBeanDefinition, GenericBeanDefinition, ChildBeanDefinition +``` + +## 3.4 关键属性 +```java +public interface BeanDefinition { + // Bean的类名 + void setBeanClassName(String beanClassName); + String getBeanClassName(); + + // 作用域(singleton、prototype等) + void setScope(String scope); + String getScope(); + + // 是否延迟初始化 + void setLazyInit(boolean lazyInit); + boolean isLazyInit(); + + // 依赖的Bean名称 + void setDependsOn(String... dependsOn); + String[] getDependsOn(); + + // 初始化方法 + void setInitMethodName(String initMethodName); + String getInitMethodName(); + + // 销毁方法 + void setDestroyMethodName(String destroyMethodName); + String getDestroyMethodName(); + + // 工厂方法名 + void setFactoryMethodName(String factoryMethodName); + String getFactoryMethodName(); +} +``` + +## 3.5 创建过程 +```java +// 编程方式创建BeanDefinition +GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); +beanDefinition.setBeanClassName("com.example.UserService"); +beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); +beanDefinition.setLazyInit(false); + +// 注册到BeanFactory +DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); +beanFactory.registerBeanDefinition("userService", beanDefinition); +``` + +# 四、BeanFactory +## 4.1 定义 +  BeanFactory是Spring IOC容器的根接口,提供了最基本的IOC功能。它是访问Spring容器的基本客户端视图。 + +## 4.2 结构 +```xml +BeanFactory (根接口) + ↑ +ListableBeanFactory, HierarchicalBeanFactory, AutowireCapableBeanFactory + ↑ +ConfigurableBeanFactory, ConfigurableListableBeanFactory + ↑ +DefaultListableBeanFactory (主要实现类) +``` + +## 4.3 核心方法 +```java +public interface BeanFactory { + // 根据名称获取Bean实例 + Object getBean(String name) throws BeansException; + + // 根据名称和类型获取Bean实例 + T getBean(String name, Class requiredType) throws BeansException; + + // 根据类型获取Bean实例 + T getBean(Class requiredType) throws BeansException; + + // 判断是否包含指定名称的Bean + boolean containsBean(String name); + + // 判断Bean是否是单例 + boolean isSingleton(String name) throws NoSuchBeanDefinitionException; + + // 判断Bean是否是原型 + boolean isPrototype(String name) throws NoSuchBeanDefinitionException; + + // 获取Bean的类型 + Class getType(String name) throws NoSuchBeanDefinitionException; +} +``` + +## 4.4 实现示例 +```java +// 创建BeanFactory实例 +DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + +// 创建BeanDefinition +GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); +beanDefinition.setBeanClassName("com.example.UserService"); + +// 注册BeanDefinition +beanFactory.registerBeanDefinition("userService", beanDefinition); + +// 获取Bean实例 +UserService userService = beanFactory.getBean("userService", UserService.class); +``` + +## 4.5 特点 +- 轻量级:功能相对简单,资源消耗少 +- 延迟加载:默认在第一次请求时才创建Bean实例 +- 基础功能:提供最基本的IOC功能 + +# 五、ApplicationContext +## 5.1 定义 +  ApplicationContext是BeanFactory的子接口,在BeanFactory的基础上提供了更多企业级功能,是Spring容器的完整实现。 + +## 5.2 结构 +```xml +BeanFactory + ↑ +ApplicationContext (扩展接口) + ↑ +ConfigurableApplicationContext + ↑ +AbstractApplicationContext + ↑ +ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, +AnnotationConfigApplicationContext, WebApplicationContext +``` + +## 5.3 特点 +- 完整的IOC功能:包含BeanFactory的所有功能 +- 预实例化单例Bean:默认在启动时创建单例Bean +- 企业级功能:支持AOP、事务管理、国际化等 +- 资源访问:统一的资源访问接口 +- 事件机制:支持应用内事件发布/订阅 + +## 5.4 refresh方法 +```java +// AbstractApplicationContext.java +/** + * Spring ApplicationContext 的核心启动方法 + * 定义了容器初始化的完整生命周期 + */ +public void refresh() throws BeansException, IllegalStateException { + // 使用同步锁确保容器启动的线程安全性,防止并发刷新 + synchronized (this.startupShutdownMonitor) { + + // [1] 准备刷新容器 - 设置启动状态,验证环境配置 + prepareRefresh(); + + // [2] 获取或创建BeanFactory - 创建DefaultListableBeanFactory实例 + // 如果是XML配置,会在这里加载和解析XML文件 + ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); + + // [3] 配置BeanFactory - 设置类加载器、注册核心BeanPostProcessor等 + prepareBeanFactory(beanFactory); + + try { + // [4] 后处理BeanFactory - 模板方法,允许子类进行特殊配置 + // Web应用会在这里注册Servlet相关的Scope + postProcessBeanFactory(beanFactory); + + // [5] 🚀 关键步骤:调用BeanFactory后置处理器 + // 执行BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor + // ConfigurationClassPostProcessor在这里扫描@Component、@Configuration等注解 + invokeBeanFactoryPostProcessors(beanFactory); + + // [6] 注册Bean后置处理器 - 注册所有BeanPostProcessor + // 包括AOP、事务、自定义的BeanPostProcessor,此时只是注册,还未执行 + registerBeanPostProcessors(beanFactory); + + // [7] 初始化消息源 - 设置国际化消息资源 + // 用于支持多语言消息解析 + initMessageSource(); + + // [8] 初始化应用事件广播器 - 创建事件发布机制的核心组件 + // 用于发布ApplicationEvent事件 + initApplicationEventMulticaster(); + + // [9] 模板方法:子类可以在这里执行特殊的刷新逻辑 + // SpringBoot在这里启动内嵌的Tomcat服务器 + onRefresh(); + + // [10] 注册监听器 - 将所有ApplicationListener注册到事件广播器 + // 包括静态指定的监听器和从BeanFactory中获取的监听器 + registerListeners(); + + // [11] 🏭 核心步骤:完成BeanFactory的初始化 + // 实例化所有非懒加载的单例Bean,执行依赖注入、AOP代理等 + finishBeanFactoryInitialization(beanFactory); + + // [12] 完成刷新过程 - 发布ContextRefreshedEvent事件 + // 标记容器启动完成,可以正常工作了 + finishRefresh(); + + } catch (BeansException ex) { + // 如果刷新过程中出现异常,需要销毁已经创建的单例Bean,防止资源泄漏 + if (logger.isWarnEnabled()) { + logger.warn("Exception encountered during context initialization - " + + "cancelling refresh attempt: " + ex); + } + + // 销毁已经创建的单例Bean + destroyBeans(); + + // 重置容器状态为未激活 + cancelRefresh(ex); + + // 重新抛出异常 + throw ex; + } finally { + // 最后重置一些公共的缓存,比如反射缓存 + resetCommonCaches(); + } + } +} +``` + +### 5.4.1 prepareRefresh() +```java +protected void prepareRefresh() { + this.startupDate = System.currentTimeMillis(); + this.closed.set(false); + this.active.set(true); + + if (logger.isInfoEnabled()) { + logger.info("Refreshing " + this); + } + + initPropertySources(); + getEnvironment().validateRequiredProperties(); + this.earlyApplicationEvents = new LinkedHashSet<>(); +} +``` + +- 这是容器启动的第一步,主要做初始化准备工作 +- 设置容器的启动时间戳和活跃状态 +- 验证必要的环境属性是否配置正确(比如通过@Value注解标记为必须的属性) +- 初始化早期事件集合,用于存储在事件多播器创建前发布的事件 +- 为整个刷新过程奠定基础状态 + +### 5.4.2 obtainFreshBeanFactory() +```java +protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { + refreshBeanFactory(); + return getBeanFactory(); +} + +// 子类实现示例 +protected final void refreshBeanFactory() throws IllegalStateException { + if (hasBeanFactory()) { + destroyBeans(); + closeBeanFactory(); + } + try { + DefaultListableBeanFactory beanFactory = createBeanFactory(); + customizeBeanFactory(beanFactory); + loadBeanDefinitions(beanFactory); + this.beanFactory = beanFactory; + } + catch (IOException ex) { + throw new ApplicationContextException("I/O error", ex); + } +} +``` + +- 创建或刷新底层的BeanFactory(Spring容器的核心工厂) +- 如果是刷新操作,会先销毁旧的BeanFactory和所有Bean实例 +- 创建新的DefaultListableBeanFactory实例 +- 加载Bean定义(从XML文件或注解配置中解析Bean的元数据) +- 这个步骤完成后,容器就知道了有哪些Bean需要管理,但还没有创建Bean实例 + +### 5.4.3 prepareBeanFactory() +```java +protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { + beanFactory.setBeanClassLoader(getClassLoader()); + beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver()); + beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); + + beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); + beanFactory.ignoreDependencyInterface(EnvironmentAware.class); + beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); + + beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); + beanFactory.registerResolvableDependency(ApplicationContext.class, this); +} +``` + +- 配置BeanFactory的基本设置和功能组件 +- 设置类加载器、SPEL表达式解析器、属性编辑器 +- 注册ApplicationContextAwareProcessor,这是实现各种Aware接口的关键 +- 忽略某些接口的依赖注入(这些接口由容器特殊处理) +- 注册可解析的依赖关系,当Bean需要这些类型时直接返回容器实例 +- 为BeanFactory添加基本的功能支持 + +### 5.4.4 postProcessBeanFactory() +```java +protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + // 空方法 - 模板方法模式 + // 子类可以覆盖此方法添加特定逻辑 +} +``` + +- 模板方法,允许子类在标准初始化后对BeanFactory进行自定义配置 +- 在Web环境中,会在这里注册Servlet相关的Scope(request、session等) +- 可以添加特定环境的BeanPostProcessor或进行其他特殊配置 +- 这是框架扩展的重要切入点 + +### 5.4.5 invokeBeanFactoryPostProcessors() +```java +protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { + PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); +} +``` + +- 🚀 这是最关键的一步,负责扫描和注册所有的Bean定义 +- 执行所有BeanFactoryPostProcessor,它们可以修改Bean的定义信息 +- 特别是ConfigurationClassPostProcessor,它负责: + 扫描@Component、@Service、@Repository等注解 + 处理@Configuration配置类 + 解析@Bean方法定义 + 处理@Import、@ComponentScan等注解 +- 这一步完成后,所有的Bean定义都已经被解析和注册 + +### 5.4.6 registerBeanPostProcessors() +```java +protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { + PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); +} +``` + +- 注册所有的BeanPostProcessor到BeanFactory中 +- 包括AOP、事务管理、自定义的Bean后置处理器等 +- 注意:此时只是注册,真正的调用要等到Bean实例化时 +- 这些处理器按照优先级顺序注册,确保执行顺序正确 +- 这是Spring AOP和事务管理等高级功能的基础 + +### 5.4.7 initMessageSource() +```java +protected void initMessageSource() { + ConfigurableListableBeanFactory beanFactory = getBeanFactory(); + if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { + this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); + } + else { + DelegatingMessageSource dms = new DelegatingMessageSource(); + this.messageSource = dms; + beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); + } +} +``` + +- 初始化国际化消息支持 +- 如果用户配置了自定义的MessageSource,就使用用户的配置 +- 否则创建默认的DelegatingMessageSource +- 支持从属性文件读取多语言消息,实现国际化功能 +- 用于解析${}占位符和国际化消息 + +### 5.4.8 initApplicationEventMulticaster() +```java +protected void initApplicationEventMulticaster() { + ConfigurableListableBeanFactory beanFactory = getBeanFactory(); + if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { + this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); + } + else { + this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); + beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); + } +} +``` + +- 初始化应用事件发布机制的核心组件 +- 如果用户配置了自定义的事件广播器,就使用用户的配置 +- 否则创建默认的SimpleApplicationEventMulticaster +- 这个组件负责将应用事件广播给所有监听器 +- 支持观察者模式,实现应用内组件间的解耦通信 + +### 5.4.9 onRefresh() - 刷新时扩展点 +```java +protected void onRefresh() throws BeansException { + // 空方法 - 模板方法 +} +``` + +- 模板方法,允许子类在特定时机执行自定义逻辑 +- 在Spring Boot中,这里会启动内嵌的Web服务器(Tomcat、Jetty等) +- 在Spring MVC中,这里会初始化HandlerMapping、HandlerAdapter等组件 +- 这是框架扩展的重要切入点,不同的ApplicationContext实现有不同的行为 + +### 5.4.10 registerListeners() +```java +protected void registerListeners() { + for (ApplicationListener listener : getApplicationListeners()) { + getApplicationEventMulticaster().addApplicationListener(listener); + } + + String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); + for (String listenerBeanName : listenerBeanNames) { + getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); + } + + // 发布早期事件 + if (this.earlyApplicationEvents != null) { + for (ApplicationEvent earlyEvent : this.earlyApplicationEvents) { + getApplicationEventMulticaster().multicastEvent(earlyEvent); + } + } +} +``` + +- 注册所有的事件监听器到事件广播器 +- 包括静态注册的监听器和从BeanFactory中获取的监听器Bean +- 发布在监听器注册前收集的早期事件 +- 确保事件发布机制完整可用,应用事件能够正确分发 + +### 5.4.11 finishBeanFactoryInitialization() +```java +protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { + if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) { + beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); + } + + if (!beanFactory.hasEmbeddedValueResolver()) { + beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); + } + + beanFactory.freezeConfiguration(); + beanFactory.preInstantiateSingletons(); +} +``` + +- 🏭 这是最核心的步骤,真正创建Bean实例 +- 初始化类型转换服务(ConversionService) +- 注册嵌入式值解析器(用于解析${}占位符) +- 冻结Bean定义,防止后续修改 +- 实例化所有非懒加载的单例Bean,这个过程中会: + 创建Bean实例 + 执行依赖注入(@Autowired、@Resource等) + 执行BeanPostProcessor(AOP代理在这里发生) + 调用初始化方法(@PostConstruct、InitializingBean) +- 这是容器启动过程中最耗时的步骤 + +### 5.4.12 finishRefresh() +```java +protected void finishRefresh() { + clearResourceCaches(); + initLifecycleProcessor(); + getLifecycleProcessor().onRefresh(); + publishEvent(new ContextRefreshedEvent(this)); + LiveBeansView.registerApplicationContext(this); +} +``` + +- 完成容器的启动过程,进行最后的清理和通知工作 +- 清除资源缓存,释放临时资源 +- 初始化生命周期处理器,管理Bean的生命周期 +- 发布ContextRefreshedEvent事件,通知所有监听器容器已启动完成 +- 注册LiveBeansView(用于监控和调试) +- 标记整个容器启动流程结束,容器进入就绪状态 + +### 5.4.13 总结 +  refresh()方法按固定顺序执行12个步骤,核心可归纳为:准备容器环境 → 解析并注册Bean定义→ 初始化事件、消息等基础设施 → 实例化所有非懒加载的单例Bean→ 完成启动并发布事件。整个过程通过模板方法模式定义,确保了扩展性和一致性。 +  核心在于两个关键扩展机制:BeanFactoryPostProcessor在Bean定义阶段介入,负责修改和注册Bean的定义信息;BeanPostProcessor在Bean实例化阶段介入,负责对创建好的Bean实例进行增强和包装。 diff --git a/docs/SpringBoot/index.md b/docs/SpringBoot/index.md new file mode 100644 index 0000000..2ac6aee --- /dev/null +++ b/docs/SpringBoot/index.md @@ -0,0 +1,9 @@ +--- +layout: doc +title: SpringBoot +--- + +# 📚 内容导航 + +- [Spring IOC简介](/SpringBoot/SpringIOC简介) +- [SpringBoot启动流程](/SpringBoot/SpringBoot启动流程) diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..ea225e6 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,18 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + + root /usr/share/nginx/html; + index index.html; + + server_name _; + + location /blog-press/ { + alias /usr/share/nginx/html/; + try_files $uri $uri/ /blog-press/index.html; + } + + location / { + try_files $uri $uri/ =404; + } +} diff --git a/package.json b/package.json index 094dedc..fbf7aad 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "vitepress": "1.6.4" }, "scripts": { - "docs:dev": "vitepress dev docs", + "docs:dev": "vitepress dev docs --host 0.0.0.0", "docs:build": "vitepress build docs", "docs:preview": "vitepress preview docs", "deploy": "npm run build && node deploy.js"