diff --git "a/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/README.md" "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/README.md"
new file mode 100644
index 0000000000000000000000000000000000000000..890320fb8cd4e4b9e0ceac79f7ed4414616f6023
--- /dev/null
+++ "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/README.md"
@@ -0,0 +1,129 @@
+# 30天完整实现数据库路由SpringBoot Starter
+
+## 📚 学习指南
+
+本目录包含30天的详细教学文件,每天一个文件,从零开始完整实现 `db-router-spring-boot-starter-1.0.2.jar` 项目。
+
+## 📖 文件说明
+
+### 已创建的文件
+
+✅ **第01-14天**:详细的教学文件,包含完整代码和解释
+- 第01天:项目初始化和Maven配置
+- 第02天:理解数据库路由和分库分表
+- 第03天:Java注解基础
+- 第04天:Java反射基础
+- 第05天:Spring AOP基础
+- 第06天:Spring Boot自动配置原理
+- 第07天:MyBatis插件机制
+- 第08天:ThreadLocal深入理解
+- 第09天:动态数据源原理
+- 第10天:策略模式设计
+- 第11天:实现配置属性类和工具类
+- 第12天:实现哈希路由策略
+- 第13天:完善AOP切面实现
+- 第14天:完善MyBatis插件
+
+✅ **第15-30天**:实现指南大纲(见 `第15-30天-后续实现指南.md`)
+
+✅ **完整项目代码清单**:所有文件的清单和实现顺序(见 `完整项目代码清单.md`)
+
+## 🎯 学习方式
+
+1. **按顺序学习**:从第01天开始,每天完成一个文件的学习和实现
+2. **动手实践**:每学一个知识点,立即写代码验证
+3. **理解原理**:不仅要会写,更要理解为什么这样写
+4. **拓展思考**:每个知识点都有拓展内容,多思考多实践
+5. **记录笔记**:记录学习心得和遇到的问题
+
+## 📝 使用说明
+
+### 第一步:阅读学习计划
+
+先阅读 `学习计划-数据库路由SpringBootStarter实现.md`,了解整体学习路线。
+
+### 第二步:按天学习
+
+1. 每天打开对应的文件(如:`第01天-项目初始化和Maven配置.md`)
+2. 阅读"今日目标"和"知识点"部分
+3. 按照"实践任务"中的步骤操作
+4. 复制代码到你的项目中(**不要只是复制,要理解每行代码**)
+5. 运行代码,验证功能
+6. 阅读"知识点拓展"部分,加深理解
+7. 完成"思考题"
+8. 在"检查清单"中打勾
+
+### 第三步:完成项目
+
+1. 按照 `完整项目代码清单.md` 检查所有文件是否完成
+2. 参考 `第15-30天-后续实现指南.md` 完成剩余功能
+3. 编写测试,验证功能
+4. 编写文档
+
+## 📋 文件结构
+
+每个教学文件都包含:
+- 📚 **今日目标**:今天要学什么
+- 🎯 **知识点**:理论知识讲解
+- 🛠️ **实践任务**:动手实现(含完整代码)
+- 🎓 **知识点拓展**:深入理解,举一反三
+- ✅ **检查清单**:验证是否完成
+- 🎯 **明日预告**:明天学什么
+- 💡 **思考题**:加深理解
+- 📚 **参考资源**:扩展阅读
+
+## ⚠️ 重要提示
+
+1. **不要只是复制代码**:理解每行代码的含义
+2. **遇到问题先思考**:自己思考10分钟,再查资料
+3. **记录问题**:把遇到的问题记录下来,逐步解决
+4. **完成拓展练习**:拓展内容很重要,不要跳过
+5. **循序渐进**:不要急于求成,每天完成当天的任务即可
+
+## ✅ 检查清单
+
+完成每天的学习后:
+- [ ] 阅读了知识点部分
+- [ ] 完成了实践任务
+- [ ] 理解了代码含义
+- [ ] 完成了拓展阅读
+- [ ] 完成了思考题
+- [ ] 在文件末尾的检查清单中打勾
+
+## 🚀 开始学习
+
+### 推荐学习路径
+
+1. **第1步**:阅读 `学习计划-数据库路由SpringBootStarter实现.md`
+2. **第2步**:阅读 `完整项目代码清单.md`,了解整体结构
+3. **第3步**:从 `第01天-项目初始化和Maven配置.md` 开始学习
+4. **第4步**:按顺序完成第01-14天的学习
+5. **第5步**:参考 `第15-30天-后续实现指南.md` 完成剩余功能
+
+### 学习时间建议
+
+- **每天学习时间**:2-3小时
+- **理论学习**:30-40%
+- **编码实践**:50-60%
+- **总结反思**:10%
+
+## 💡 遇到问题怎么办?
+
+1. **先思考**:自己先思考10分钟
+2. **查文档**:查阅相关文档(每个文件末尾都有参考资源)
+3. **看源码**:看Spring、MyBatis的源码
+4. **问问题**:在技术社区提问
+5. **调试**:使用调试工具逐步排查
+
+## 🎉 完成后的收获
+
+完成30天的学习后,你将:
+- ✅ 完全理解数据库路由的原理
+- ✅ 掌握Spring Boot Starter的开发
+- ✅ 理解AOP、反射、注解等核心概念
+- ✅ 能够独立开发类似的中间件
+- ✅ 知其然,知其所以然
+
+---
+
+**祝你学习顺利!有问题随时记录,每天进步一点点!** 🎉
diff --git "a/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\345\256\214\346\225\264\351\241\271\347\233\256\344\273\243\347\240\201\346\270\205\345\215\225.md" "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\345\256\214\346\225\264\351\241\271\347\233\256\344\273\243\347\240\201\346\270\205\345\215\225.md"
new file mode 100644
index 0000000000000000000000000000000000000000..05040e86e4e95befcf1afd6ad0f8fde663d974a5
--- /dev/null
+++ "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\345\256\214\346\225\264\351\241\271\347\233\256\344\273\243\347\240\201\346\270\205\345\215\225.md"
@@ -0,0 +1,207 @@
+# 完整项目代码清单
+
+## 📚 说明
+
+本文档列出了实现 `db-router-spring-boot-starter` 项目所需的所有代码文件。按照30天的学习计划,逐步实现这些文件。
+
+---
+
+## 📁 项目结构
+
+```
+db-router-spring-boot-starter/
+├── pom.xml
+├── src/
+│ ├── main/
+│ │ ├── java/
+│ │ │ └── cn/bugstack/middleware/db/router/
+│ │ │ ├── annotation/
+│ │ │ │ ├── DBRouter.java
+│ │ │ │ └── DBRouterStrategy.java
+│ │ │ ├── config/
+│ │ │ │ └── DataSourceAutoConfig.java
+│ │ │ ├── dynamic/
+│ │ │ │ ├── DynamicDataSource.java
+│ │ │ │ └── DynamicMybatisPlugin.java
+│ │ │ ├── strategy/
+│ │ │ │ ├── IDBRouterStrategy.java
+│ │ │ │ └── impl/
+│ │ │ │ └── DBRouterStrategyHashCode.java
+│ │ │ ├── util/
+│ │ │ │ ├── StringUtils.java
+│ │ │ │ └── PropertyUtil.java
+│ │ │ ├── DBContextHolder.java
+│ │ │ ├── DBRouterBase.java
+│ │ │ ├── DBRouterConfig.java
+│ │ │ └── DBRouterJoinPoint.java
+│ │ └── resources/
+│ │ └── META-INF/
+│ │ └── spring.factories
+│ └── test/
+│ └── java/
+```
+
+---
+
+## 📝 文件清单
+
+### 1. pom.xml
+**位置**:项目根目录
+**说明**:Maven配置文件,包含所有依赖
+**实现日期**:第01天
+
+### 2. DBRouter.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/annotation/`
+**说明**:数据库路由注解
+**实现日期**:第03天
+
+### 3. DBRouterStrategy.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/annotation/`
+**说明**:数据库路由策略注解
+**实现日期**:第03天
+
+### 4. PropertyUtil.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/util/`
+**说明**:属性工具类,用于反射获取属性值
+**实现日期**:第04天
+
+### 5. StringUtils.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/util/`
+**说明**:字符串工具类
+**实现日期**:第11天
+
+### 6. DBRouterConfig.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/`
+**说明**:数据库路由配置类
+**实现日期**:第11天
+
+### 7. IDBRouterStrategy.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/strategy/`
+**说明**:路由策略接口
+**实现日期**:第10天
+
+### 8. DBRouterStrategyHashCode.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/strategy/impl/`
+**说明**:哈希路由策略实现
+**实现日期**:第12天
+
+### 9. DBContextHolder.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/`
+**说明**:数据库路由上下文持有者,使用ThreadLocal存储路由信息
+**实现日期**:第08天
+
+### 10. DBRouterBase.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/`
+**说明**:数据库路由基类
+**实现日期**:第12天
+
+### 11. DynamicDataSource.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/dynamic/`
+**说明**:动态数据源,继承AbstractRoutingDataSource
+**实现日期**:第09天
+
+### 12. DynamicMybatisPlugin.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/dynamic/`
+**说明**:MyBatis插件,用于修改SQL中的表名
+**实现日期**:第07天、第14天
+
+### 13. DBRouterJoinPoint.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/`
+**说明**:AOP切面,拦截带@DBRouter注解的方法
+**实现日期**:第05天、第13天
+
+### 14. DataSourceAutoConfig.java
+**位置**:`src/main/java/cn/bugstack/middleware/db/router/config/`
+**说明**:数据源自动配置类
+**实现日期**:第06天、第15天
+
+### 15. spring.factories
+**位置**:`src/main/resources/META-INF/`
+**说明**:Spring Boot自动配置入口文件
+**实现日期**:第16天
+
+---
+
+## 🔄 实现顺序
+
+### 第一阶段:基础知识(第01-10天)
+1. 项目初始化(pom.xml)
+2. 理解数据库路由概念
+3. 实现注解(DBRouter、DBRouterStrategy)
+4. 实现工具类(PropertyUtil)
+5. 理解AOP和实现切面(DBRouterJoinPoint)
+6. 理解自动配置(DataSourceAutoConfig)
+7. 实现MyBatis插件(DynamicMybatisPlugin)
+8. 实现上下文持有者(DBContextHolder)
+9. 实现动态数据源(DynamicDataSource)
+10. 设计策略接口(IDBRouterStrategy)
+
+### 第二阶段:核心实现(第11-20天)
+11. 实现配置类和工具类(DBRouterConfig、StringUtils)
+12. 实现路由策略(DBRouterStrategyHashCode、DBRouterBase)
+13. 完善AOP切面(DBRouterJoinPoint)
+14. 完善MyBatis插件(DynamicMybatisPlugin)
+15. 完善自动配置(DataSourceAutoConfig)
+16. 创建spring.factories
+17-20. 测试和优化
+
+### 第三阶段:功能完善(第21-30天)
+21-30. 功能完善、测试、文档
+
+---
+
+## 📋 检查清单
+
+完成每个文件后,在对应日期打勾:
+
+### 注解
+- [ ] DBRouter.java(第03天)
+- [ ] DBRouterStrategy.java(第03天)
+
+### 配置
+- [ ] DBRouterConfig.java(第11天)
+- [ ] DataSourceAutoConfig.java(第06天、第15天)
+
+### 核心类
+- [ ] DBContextHolder.java(第08天)
+- [ ] DBRouterJoinPoint.java(第05天、第13天)
+- [ ] DBRouterBase.java(第12天)
+
+### 动态数据源
+- [ ] DynamicDataSource.java(第09天)
+- [ ] DynamicMybatisPlugin.java(第07天、第14天)
+
+### 策略
+- [ ] IDBRouterStrategy.java(第10天)
+- [ ] DBRouterStrategyHashCode.java(第12天)
+
+### 工具类
+- [ ] StringUtils.java(第11天)
+- [ ] PropertyUtil.java(第04天)
+
+### 配置文件
+- [ ] pom.xml(第01天)
+- [ ] spring.factories(第16天)
+
+---
+
+## 🎯 使用说明
+
+1. **按顺序学习**:从第01天开始,每天完成一个文件
+2. **理解原理**:不要只是复制代码,要理解为什么这样写
+3. **动手实践**:每学一个知识点就写代码验证
+4. **记录问题**:遇到问题记录下来,逐步解决
+5. **拓展思考**:完成拓展练习,加深理解
+
+---
+
+## 💡 提示
+
+- 所有代码都在对应的日期文件中
+- 每个文件都有详细的代码和解释
+- 遇到问题可以查看对应日期的文件
+- 完成所有文件后,项目就可以使用了
+
+---
+
+**祝你学习顺利!** 🎉
diff --git "a/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25401\345\244\251-\351\241\271\347\233\256\345\210\235\345\247\213\345\214\226\345\222\214Maven\351\205\215\347\275\256.md" "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25401\345\244\251-\351\241\271\347\233\256\345\210\235\345\247\213\345\214\226\345\222\214Maven\351\205\215\347\275\256.md"
new file mode 100644
index 0000000000000000000000000000000000000000..6abc3ad4333a0c928527a6dbd2776718e0af360c
--- /dev/null
+++ "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25401\345\244\251-\351\241\271\347\233\256\345\210\235\345\247\213\345\214\226\345\222\214Maven\351\205\215\347\275\256.md"
@@ -0,0 +1,669 @@
+# 第01天:项目初始化和Maven配置
+
+## 📚 今日目标
+
+1. 理解什么是Spring Boot
+2. 理解什么是Spring Boot Starter
+3. 创建Maven项目结构
+4. 配置pom.xml文件
+5. 理解项目依赖关系
+
+---
+
+## 🎯 知识点0:什么是Spring Boot?(先理解这个)
+
+### 生活中的例子
+
+**传统Java开发 vs Spring Boot开发**
+
+**传统方式(复杂)**:
+```
+想象你要做一道菜:
+1. 买锅(配置Tomcat服务器)
+2. 买调料(配置各种XML文件)
+3. 准备食材(写很多配置代码)
+4. 生火(启动服务器)
+5. 炒菜(写业务代码)
+```
+
+**Spring Boot方式(简单)**:
+```
+Spring Boot就像"外卖套餐":
+1. 打开包装(引入依赖)
+2. 加热(运行main方法)
+3. 开吃(直接写业务代码)
+```
+
+### 最简单的例子
+
+**传统Spring项目**(需要配置很多XML):
+
+```java
+// 1. 需要web.xml配置
+// 2. 需要applicationContext.xml配置
+// 3. 需要配置数据源、事务等
+// 4. 需要部署到Tomcat服务器
+// ... 很多配置
+```
+
+**Spring Boot项目**(几乎零配置):
+
+```java
+// 1. 创建一个类
+@SpringBootApplication
+public class MyApp {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApp.class, args);
+ }
+}
+
+// 2. 运行main方法
+// 3. 完成!服务器自动启动,可以访问了
+```
+
+### Spring Boot的核心特点
+
+**1. 自动配置(Auto Configuration)**
+```
+传统方式:需要手动配置每个组件
+Spring Boot:检测到classpath中的类,自动配置
+```
+
+**例子**:
+```java
+// 传统方式:需要手动配置数据源
+@Configuration
+public class DataSourceConfig {
+ @Bean
+ public DataSource dataSource() {
+ // 写很多配置代码
+ }
+}
+
+// Spring Boot:引入依赖,自动配置
+// 只需要在application.yml中写:
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/test
+ username: root
+ password: 123456
+// 数据源自动创建好了!
+```
+
+**2. 起步依赖(Starter Dependencies)**
+```
+传统方式:需要一个个引入依赖,还要处理版本冲突
+Spring Boot:引入一个starter,自动引入所有相关依赖
+```
+
+**例子**:
+```xml
+
+
+ org.springframework
+ spring-web
+
+
+ org.springframework
+ spring-webmvc
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+```
+
+**3. 内嵌服务器(Embedded Server)**
+```
+传统方式:需要安装Tomcat,打包成war,部署到服务器
+Spring Boot:内嵌Tomcat,打包成jar,直接运行
+```
+
+**例子**:
+```bash
+# 传统方式
+1. 打包成war文件
+2. 部署到Tomcat
+3. 启动Tomcat
+4. 访问应用
+
+# Spring Boot方式
+1. 打包成jar文件
+2. java -jar app.jar
+3. 完成!直接访问
+```
+
+### 最简单的完整例子
+
+**创建一个Web接口**:
+
+```java
+// 1. 主类
+@SpringBootApplication
+public class HelloApp {
+ public static void main(String[] args) {
+ SpringApplication.run(HelloApp.class, args);
+ }
+}
+
+// 2. 控制器(处理HTTP请求)
+@RestController
+public class HelloController {
+ @GetMapping("/hello")
+ public String hello() {
+ return "Hello Spring Boot!";
+ }
+}
+
+// 3. 运行main方法
+// 4. 浏览器访问:http://localhost:8080/hello
+// 5. 看到:Hello Spring Boot!
+```
+
+**就这么简单!**
+- 不需要配置web.xml
+- 不需要配置Tomcat
+- 不需要部署
+- 直接运行,直接访问
+
+### 为什么用Spring Boot?
+
+**传统Spring的问题**:
+- ❌ 配置复杂(XML、Java配置)
+- ❌ 依赖管理困难(版本冲突)
+- ❌ 部署复杂(需要服务器)
+- ❌ 开发效率低
+
+**Spring Boot的优势**:
+- ✅ 零配置(约定优于配置)
+- ✅ 自动配置(开箱即用)
+- ✅ 内嵌服务器(直接运行)
+- ✅ 开发效率高
+
+### 总结
+
+**Spring Boot = Spring框架 + 自动配置 + 起步依赖 + 内嵌服务器**
+
+**核心思想**:**约定优于配置**
+- 不需要配置的,就不配置
+- 有默认值的,就用默认值
+- 需要配置的,才配置
+
+---
+
+## 🎯 知识点1:什么是Spring Boot Starter?
+
+### 为什么需要Starter?
+
+**问题场景**:
+- 每次使用某个框架(如MyBatis),都要手动配置很多Bean
+- 配置复杂,容易出错
+- 不同项目重复配置
+
+**解决方案**:Spring Boot Starter
+- 把常用配置打包成一个依赖
+- 引入依赖后自动配置
+- 开箱即用,零配置
+
+**例子**:
+```xml
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+
+
+
+```
+
+### 我们的目标
+
+创建一个 `db-router-spring-boot-starter`,让用户:
+1. 引入依赖
+2. 配置几个参数
+3. 使用 `@DBRouter` 注解
+4. 自动实现分库分表
+
+---
+
+## 🎯 知识点2:Maven项目结构
+
+### 标准Maven项目结构
+
+```
+db-router-spring-boot-starter/
+├── pom.xml # Maven配置文件
+├── src/
+│ ├── main/
+│ │ ├── java/ # Java源代码
+│ │ │ └── cn/bugstack/middleware/db/router/
+│ │ │ ├── annotation/ # 注解
+│ │ │ ├── config/ # 配置类
+│ │ │ ├── dynamic/ # 动态数据源
+│ │ │ ├── strategy/ # 路由策略
+│ │ │ └── util/ # 工具类
+│ │ └── resources/
+│ │ └── META-INF/
+│ │ └── spring.factories # 自动配置入口
+│ └── test/ # 测试代码
+│ └── java/
+```
+
+### 为什么这样组织?
+
+- **annotation**:存放自定义注解(@DBRouter等)
+- **config**:Spring配置类(自动配置)
+- **dynamic**:动态数据源相关类
+- **strategy**:路由策略(策略模式)
+- **util**:工具类(字符串、属性等)
+
+---
+
+## 🛠️ 实践任务1:创建项目结构
+
+### 步骤1:创建目录
+
+在你的项目根目录执行:
+
+```bash
+mkdir -p src/main/java/cn/bugstack/middleware/db/router/{annotation,config,dynamic,strategy/impl,util}
+mkdir -p src/main/resources/META-INF
+mkdir -p src/test/java
+```
+
+### 步骤2:验证结构
+
+```bash
+tree src/ # 如果没有tree命令,用 find src -type d
+```
+
+应该看到:
+```
+src/
+├── main
+│ ├── java
+│ │ └── cn
+│ │ └── bugstack
+│ │ └── middleware
+│ │ └── db
+│ │ └── router
+│ │ ├── annotation
+│ │ ├── config
+│ │ ├── dynamic
+│ │ ├── strategy
+│ │ │ └── impl
+│ │ └── util
+│ └── resources
+│ └── META-INF
+└── test
+ └── java
+```
+
+---
+
+## 🛠️ 实践任务2:创建pom.xml
+
+### 完整pom.xml代码
+
+在项目根目录创建 `pom.xml`:
+
+```xml
+
+
+ 4.0.0
+
+
+ cn.bugstack.middleware
+ db-router-spring-boot-starter
+ 1.0.2
+ jar
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.3.5.RELEASE
+
+
+
+
+ UTF-8
+ 1.8
+ 1.8
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 2.1.4
+
+
+
+
+
+
+
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.9.4
+
+
+
+
+
+ commons-lang
+ commons-lang
+ 2.6
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ db-router-spring-boot-starter
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+
+```
+
+### 依赖说明
+
+**📋 依赖分类总结**:
+
+**✅ 必须依赖(核心功能需要)**:
+1. spring-boot-starter - Spring Boot核心
+2. spring-boot-autoconfigure - 自动配置
+3. spring-boot-starter-aop - AOP切面
+4. mybatis-spring-boot-starter - MyBatis插件
+5. commons-beanutils - 反射获取属性
+6. commons-lang - 字符串工具
+
+**❌ 可选依赖(已注释,可删除)**:
+1. mysql-connector-java - 用户项目会自己引入
+2. fastjson - 代码中没有使用
+3. junit - spring-boot-starter-test已包含
+
+**⚠️ 可选但建议保留**:
+1. spring-boot-configuration-processor - IDE提示(optional=true,不影响运行时)
+2. spring-boot-starter-test - 测试用(scope=test,不影响打包)
+
+**📝 关于HikariCP的说明**:
+- 第15天的DataSourceAutoConfig代码中使用了HikariCP创建数据源
+- 但pom.xml中没有HikariCP依赖,因为:
+ 1. 用户项目通常会引入spring-boot-starter-jdbc(已包含HikariCP)
+ 2. 或者用户自己选择连接池(Druid、HikariCP等)
+ 3. 我们的starter不应该强制指定连接池
+- 如果测试时需要,可以临时添加:
+ ```xml
+
+ com.zaxxer
+ HikariCP
+
+ ```
+
+---
+
+#### 1. Spring Boot Starter
+```xml
+
+ org.springframework.boot
+ spring-boot-starter
+
+```
+**作用**:Spring Boot核心功能,包含自动配置、日志等
+
+#### 2. Spring Boot Autoconfigure
+```xml
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+```
+**作用**:自动配置的核心,我们用它来实现自动配置
+
+#### 3. Spring Boot AOP
+```xml
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+```
+**作用**:AOP功能,用于拦截方法,实现路由逻辑
+
+#### 4. MyBatis Spring Boot Starter
+```xml
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+
+```
+**作用**:MyBatis集成,我们需要拦截SQL修改表名
+
+#### 5. Commons BeanUtils
+```xml
+
+ commons-beanutils
+ commons-beanutils
+
+```
+**作用**:通过反射获取对象属性值(如获取userId)
+**是否必须**:✅ 必须 - PropertyUtil.getProperty()方法使用
+
+#### 6. Commons Lang
+```xml
+
+ commons-lang
+ commons-lang
+
+```
+**作用**:字符串工具类(isBlank等方法)
+**是否必须**:✅ 必须 - StringUtils使用
+
+#### 7. MySQL驱动
+**是否必须**:❌ 可选 - 用户项目会自己引入数据库驱动
+
+#### 8. FastJSON
+**是否必须**:❌ 可选 - 代码中没有使用,可以删除
+
+#### 9. 测试依赖
+**是否必须**:❌ 可选 - 只在测试时需要(scope=test)
+
+---
+
+## 🎓 知识点拓展
+
+### 拓展1:Maven依赖作用域(Scope)
+
+```xml
+compile
+provided
+runtime
+test
+system
+```
+
+**为什么spring-boot-configuration-processor用optional?**
+- `optional=true` 表示这个依赖不会传递
+- 只在开发时用于IDE提示,运行时不需要
+- 避免用户项目引入不必要的依赖
+
+### 拓展2:Spring Boot版本选择
+
+**为什么用2.3.5?**
+- 这是原项目使用的版本
+- 2.x版本稳定,兼容性好
+- 3.x版本需要Java 17+,门槛更高
+
+**如何选择版本?**
+- 生产环境:选择稳定版本(如2.7.x)
+- 学习环境:可以尝试最新版本
+- 注意:不同版本API可能有差异
+
+### 拓展3:Maven坐标(Coordinates)
+
+```xml
+cn.bugstack.middleware
+db-router-spring-boot-starter
+1.0.2
+```
+
+**命名规范**:
+- groupId:通常是域名倒写(如com.company.project)
+- artifactId:项目名,小写,用连字符
+- version:语义化版本(主版本.次版本.修订版本)
+
+---
+
+## ✅ 今日检查清单
+
+- [ ] 创建了完整的项目目录结构
+- [ ] 创建了pom.xml文件
+- [ ] 理解了每个依赖的作用
+- [ ] 能够解释为什么需要这些依赖
+- [ ] 完成了拓展阅读
+
+---
+
+## 🎯 明日预告
+
+明天我们将学习:
+- 什么是数据库路由
+- 为什么需要分库分表
+- 路由的基本原理
+
+---
+
+## 💡 思考题
+
+1. 如果不用Spring Boot Starter,用户需要手动配置哪些东西?
+2. 为什么starter的依赖要用`optional=true`?
+3. Maven的``标签有什么作用?
+
+---
+
+## 📚 参考资源
+
+- [Spring Boot官方文档](https://spring.io/projects/spring-boot)
+- [Maven官方文档](https://maven.apache.org/guides/)
+- [Spring Boot Starter开发指南](https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters)
diff --git "a/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25402\345\244\251-\347\220\206\350\247\243\346\225\260\346\215\256\345\272\223\350\267\257\347\224\261\345\222\214\345\210\206\345\272\223\345\210\206\350\241\250.md" "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25402\345\244\251-\347\220\206\350\247\243\346\225\260\346\215\256\345\272\223\350\267\257\347\224\261\345\222\214\345\210\206\345\272\223\345\210\206\350\241\250.md"
new file mode 100644
index 0000000000000000000000000000000000000000..c71d22429ac2ac960654a8a0874ea113aab38e0e
--- /dev/null
+++ "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25402\345\244\251-\347\220\206\350\247\243\346\225\260\346\215\256\345\272\223\350\267\257\347\224\261\345\222\214\345\210\206\345\272\223\345\210\206\350\241\250.md"
@@ -0,0 +1,340 @@
+# 第02天:理解数据库路由和分库分表
+
+## 📚 今日目标
+
+1. 理解什么是数据库路由
+2. 理解为什么需要分库分表
+3. 理解路由的基本原理
+4. 画图理解分库分表架构
+
+---
+
+## 🎯 知识点1:什么是数据库路由?
+
+### 生活中的例子
+
+**快递分拣**:
+- 快递员根据地址,把包裹送到不同的分拣中心
+- 北京 → 北京分拣中心
+- 上海 → 上海分拣中心
+
+**数据库路由**:
+- 根据路由键(如用户ID),把数据存到不同的数据库/表
+- 用户ID 1-1000万 → 数据库1,表1
+- 用户ID 1000万-2000万 → 数据库2,表2
+
+### 核心概念
+
+**路由键(Router Key)**:
+- 用来决定数据存在哪里的字段
+- 通常是业务主键(如用户ID、订单ID)
+- 必须保证:相同路由键 → 相同库表
+
+**路由算法**:
+- 根据路由键计算目标库和表
+- 常用算法:哈希、取模、范围等
+
+---
+
+## 🎯 知识点2:为什么需要分库分表?
+
+### 问题场景
+
+**单库单表的问题**:
+
+```
+用户表(user)
+├── 1亿条数据
+├── 查询越来越慢
+├── 索引越来越大
+└── 数据库压力巨大
+```
+
+**性能瓶颈**:
+1. **查询慢**:数据量大,即使有索引也很慢
+2. **写入慢**:插入数据需要维护索引
+3. **锁竞争**:高并发时锁竞争激烈
+4. **单点故障**:一个数据库挂了,整个系统不可用
+
+### 解决方案:分库分表
+
+**分表(水平分表)**:
+```
+原来:user(1亿条)
+现在:
+├── user_01(2500万条)
+├── user_02(2500万条)
+├── user_03(2500万条)
+└── user_04(2500万条)
+```
+
+**分库(水平分库)**:
+```
+原来:db1(1亿条)
+现在:
+├── db1(2500万条)
+├── db2(2500万条)
+├── db3(2500万条)
+└── db4(2500万条)
+```
+
+**效果**:
+- 单表数据量减少 → 查询更快
+- 分散到多个库 → 并发能力提升
+- 单个库故障 → 不影响其他库
+
+---
+
+## 🎯 知识点3:路由算法
+
+### 算法1:哈希路由
+
+**原理**:
+```java
+int dbIndex = Math.abs(userId.hashCode()) % dbCount;
+int tbIndex = Math.abs(userId.hashCode()) % tbCount;
+```
+
+**例子**:
+```
+userId = "12345678"
+hashCode = 12345678.hashCode() = 12345678
+dbCount = 2
+tbCount = 4
+
+dbIndex = 12345678 % 2 = 0 → db01
+tbIndex = 12345678 % 4 = 2 → user_02
+```
+
+**优点**:
+- 数据分布均匀
+- 相同userId总是路由到相同位置
+
+**缺点**:
+- 扩容困难(需要重新分布数据)
+
+### 算法2:取模路由
+
+**原理**:
+```java
+int dbIndex = userId % dbCount;
+int tbIndex = userId % tbCount;
+```
+
+**例子**:
+```
+userId = 12345678
+dbCount = 2
+tbCount = 4
+
+dbIndex = 12345678 % 2 = 0 → db01
+tbIndex = 12345678 % 4 = 2 → user_02
+```
+
+**优点**:
+- 简单直接
+- 计算快速
+
+**缺点**:
+- 只适用于数字类型路由键
+- 扩容困难
+
+### 算法3:范围路由
+
+**原理**:
+```java
+if (userId >= 1 && userId <= 10000000) {
+ dbIndex = 0; // db01
+} else if (userId > 10000000 && userId <= 20000000) {
+ dbIndex = 1; // db02
+}
+```
+
+**优点**:
+- 扩容相对容易(只需添加新范围)
+- 查询范围数据方便
+
+**缺点**:
+- 数据分布可能不均匀
+- 需要维护范围配置
+
+---
+
+## 🛠️ 实践任务:画图理解架构
+
+### 任务1:画分库分表架构图
+
+用纸笔或画图工具画出:
+
+```
+用户请求(userId=12345678)
+ ↓
+路由计算
+ ↓
+dbIndex = 0, tbIndex = 2
+ ↓
+选择数据源:db01
+ ↓
+修改SQL:user → user_02
+ ↓
+执行SQL
+```
+
+### 任务2:理解数据分布
+
+假设:
+- 2个数据库(db01, db02)
+- 每个库4张表(user_01, user_02, user_03, user_04)
+
+**问题**:
+1. userId=1 应该存在哪里?
+2. userId=10000001 应该存在哪里?
+3. 如何保证相同userId总是路由到相同位置?
+
+**答案**:
+```
+userId=1:
+ hashCode = 1
+ dbIndex = 1 % 2 = 1 → db02
+ tbIndex = 1 % 4 = 1 → user_01
+ 结果:db02.user_01
+
+userId=10000001:
+ hashCode = 10000001
+ dbIndex = 10000001 % 2 = 1 → db02
+ tbIndex = 10000001 % 4 = 1 → user_01
+ 结果:db02.user_01
+```
+
+---
+
+## 🎓 知识点拓展
+
+### 拓展1:垂直分表 vs 水平分表
+
+**垂直分表**:
+```
+原来:user表
+├── id
+├── name
+├── age
+├── email
+├── address
+└── description(大字段)
+
+现在:
+├── user_base(id, name, age)
+└── user_detail(id, email, address, description)
+```
+**场景**:某些字段很大但不常用
+
+**水平分表**:
+```
+原来:user(1亿条)
+现在:
+├── user_01(2500万条)
+├── user_02(2500万条)
+├── user_03(2500万条)
+└── user_04(2500万条)
+```
+**场景**:数据量大,需要分散
+
+### 拓展2:分库分表的挑战
+
+**1. 跨库查询**
+```
+问题:查询所有订单总金额
+原来:SELECT SUM(amount) FROM order
+现在:需要查询多个库,然后汇总
+```
+
+**解决方案**:
+- 避免跨库查询(设计时考虑)
+- 使用中间件(如ShardingSphere)
+- 数据汇总表
+
+**2. 分布式事务**
+```
+问题:用户下单需要:
+1. 扣减库存(db1)
+2. 创建订单(db2)
+3. 扣减余额(db3)
+如何保证原子性?
+```
+
+**解决方案**:
+- 避免跨库事务(尽量单库完成)
+- 使用分布式事务(如Seata)
+- 最终一致性(消息队列)
+
+**3. 扩容**
+```
+问题:2个库不够用了,要扩容到4个库
+如何迁移数据?
+```
+
+**解决方案**:
+- 双写方案(新旧库同时写)
+- 数据迁移工具
+- 平滑扩容
+
+### 拓展3:路由键选择
+
+**好的路由键**:
+- ✅ 业务主键(用户ID、订单ID)
+- ✅ 分布均匀
+- ✅ 查询时经常用到
+
+**不好的路由键**:
+- ❌ 时间戳(数据倾斜)
+- ❌ 随机值(无法定位)
+- ❌ 很少查询的字段
+
+**例子**:
+```
+订单表路由键选择:
+
+✅ 用户ID(userId)
+ - 用户查询自己的订单
+ - 数据分布均匀
+
+❌ 订单时间(createTime)
+ - 最近的数据都在一个库
+ - 数据倾斜严重
+```
+
+---
+
+## ✅ 今日检查清单
+
+- [ ] 理解了数据库路由的概念
+- [ ] 理解了为什么需要分库分表
+- [ ] 理解了路由算法的原理
+- [ ] 画出了分库分表架构图
+- [ ] 完成了拓展阅读
+- [ ] 思考了路由键的选择
+
+---
+
+## 🎯 明日预告
+
+明天我们将学习:
+- Java注解(Annotation)基础
+- 如何自定义注解
+- 注解的元注解
+
+---
+
+## 💡 思考题
+
+1. 如果路由键是字符串(如手机号),如何计算路由?
+2. 分库分表后,如何保证全局ID唯一?
+3. 如果某个库的数据量特别大,怎么办?
+
+---
+
+## 📚 参考资源
+
+- [分库分表原理](https://www.cnblogs.com/littlecharacter/p/9342369.html)
+- [数据库分片策略](https://shardingsphere.apache.org/document/current/cn/features/sharding/concept/sharding/)
+- [分布式系统设计](https://github.com/donnemartin/system-design-primer)
diff --git "a/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25403\345\244\251-Java\346\263\250\350\247\243\345\237\272\347\241\200.md" "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25403\345\244\251-Java\346\263\250\350\247\243\345\237\272\347\241\200.md"
new file mode 100644
index 0000000000000000000000000000000000000000..f5374b81ef22388e2bcb6d631fb4605c5ff2aca0
--- /dev/null
+++ "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25403\345\244\251-Java\346\263\250\350\247\243\345\237\272\347\241\200.md"
@@ -0,0 +1,308 @@
+# 第03天:Java注解基础
+
+## 📚 今日目标
+
+1. 理解Java注解的概念
+2. 学会自定义注解
+3. 理解注解的元注解
+4. 实现@DBRouter注解
+
+---
+
+## 🎯 知识点1:什么是注解?
+
+### 生活中的例子
+
+**标签**:
+- 商品上的标签:价格、产地、保质期
+- 代码上的标签:@Override、@Deprecated
+
+**注解的作用**:
+- 给代码添加元数据(metadata)
+- 告诉编译器、框架如何处理代码
+- 运行时可以通过反射读取
+
+### Java内置注解
+
+```java
+@Override // 标记方法重写父类方法
+@Deprecated // 标记方法已过时
+@SuppressWarnings("unchecked") // 抑制警告
+```
+
+---
+
+## 🎯 知识点2:注解的元注解
+
+### 元注解(Meta-Annotation)
+
+**定义**:用来定义注解的注解
+
+### @Target:指定注解可以用在哪里
+
+```java
+@Target(ElementType.METHOD) // 只能用在方法上
+@Target(ElementType.TYPE) // 只能用在类上
+@Target({ElementType.METHOD, ElementType.TYPE}) // 可以用在方法和类上
+```
+
+**ElementType枚举值**:
+- `TYPE`:类、接口、枚举
+- `METHOD`:方法
+- `FIELD`:字段
+- `PARAMETER`:参数
+- `CONSTRUCTOR`:构造函数
+- `LOCAL_VARIABLE`:局部变量
+- `ANNOTATION_TYPE`:注解类型
+- `PACKAGE`:包
+
+### @Retention:指定注解保留到什么时候
+
+```java
+@Retention(RetentionPolicy.SOURCE) // 只在源码中,编译后丢弃
+@Retention(RetentionPolicy.CLASS) // 编译到class文件,运行时不可用
+@Retention(RetentionPolicy.RUNTIME) // 运行时可用(可以通过反射读取)
+```
+
+**为什么用RUNTIME?**
+- 我们需要在运行时读取注解
+- 通过反射获取注解信息
+- 根据注解信息执行路由逻辑
+
+### @Documented:生成JavaDoc
+
+```java
+@Documented // 注解信息会包含在JavaDoc中
+```
+
+### @Inherited:可以继承
+
+```java
+@Inherited // 子类会继承父类的注解
+```
+
+---
+
+## 🛠️ 实践任务1:创建@DBRouter注解
+
+### 步骤1:创建注解文件
+
+在 `src/main/java/cn/bugstack/middleware/db/router/annotation/` 目录下创建 `DBRouter.java`:
+
+```java
+package cn.bugstack.middleware.db.router.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 数据库路由注解
+ *
+ * 使用方式:
+ * @DBRouter(key = "userId")
+ * public void queryUser(User user) {
+ * // 方法实现
+ * }
+ *
+ * @author 小傅哥
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface DBRouter {
+
+ /**
+ * 分库分表字段
+ * 用于指定路由键,如:userId、orderId等
+ *
+ * @return 路由键字段名
+ */
+ String key() default "";
+}
+```
+
+### 代码解释
+
+1. **@Documented**:生成JavaDoc时会包含这个注解
+2. **@Retention(RetentionPolicy.RUNTIME)**:运行时可用,可以通过反射读取
+3. **@Target({ElementType.METHOD, ElementType.TYPE})**:可以用在方法和类上
+4. **String key() default ""**:注解属性,默认值为空字符串
+
+### 使用示例
+
+```java
+// 方法级别使用
+@DBRouter(key = "userId")
+public User queryUser(User user) {
+ return userMapper.selectById(user.getUserId());
+}
+
+// 类级别使用
+@DBRouter(key = "userId")
+public class UserService {
+ // ...
+}
+```
+
+---
+
+## 🛠️ 实践任务2:创建@DBRouterStrategy注解
+
+### 步骤1:创建注解文件
+
+在同一个目录下创建 `DBRouterStrategy.java`:
+
+```java
+package cn.bugstack.middleware.db.router.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 数据库路由策略注解
+ *
+ * 用于类级别,指定是否分表
+ *
+ * @author 小傅哥
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface DBRouterStrategy {
+
+ /**
+ * 是否分表
+ * true:需要分表,SQL中的表名会被替换
+ * false:只分库,不分表
+ *
+ * @return 是否分表
+ */
+ boolean splitTable() default false;
+}
+```
+
+### 使用示例
+
+```java
+@DBRouterStrategy(splitTable = true)
+public class UserMapper {
+
+ @DBRouter(key = "userId")
+ public User selectById(Long userId) {
+ // SQL: SELECT * FROM user WHERE id = ?
+ // 会被替换为: SELECT * FROM user_01 WHERE id = ?
+ }
+}
+```
+
+---
+
+## 🎓 知识点拓展
+
+### 拓展1:注解属性的类型
+
+**允许的类型**:
+- 基本类型(int, long, boolean等)
+- String
+- Class
+- 枚举
+- 注解
+- 以上类型的数组
+
+**例子**:
+```java
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MyAnnotation {
+ String value(); // String类型
+ int count() default 0; // int类型,有默认值
+ Class> clazz(); // Class类型
+ ElementType[] types(); // 数组类型
+ DBRouter router(); // 注解类型
+}
+```
+
+### 拓展2:注解的默认值
+
+```java
+public @interface MyAnnotation {
+ String value() default ""; // 有默认值,使用时可以不写
+ int count(); // 没有默认值,使用时必须写
+}
+
+// 使用
+@MyAnnotation(count = 10) // value使用默认值
+@MyAnnotation(value = "test", count = 10) // 都指定
+```
+
+### 拓展3:通过反射读取注解
+
+```java
+// 获取方法上的注解
+Method method = UserService.class.getMethod("queryUser", User.class);
+DBRouter annotation = method.getAnnotation(DBRouter.class);
+if (annotation != null) {
+ String key = annotation.key(); // 获取路由键
+ System.out.println("路由键: " + key);
+}
+
+// 获取类上的注解
+DBRouterStrategy strategy = UserService.class.getAnnotation(DBRouterStrategy.class);
+if (strategy != null) {
+ boolean splitTable = strategy.splitTable();
+ System.out.println("是否分表: " + splitTable);
+}
+```
+
+### 拓展4:注解的继承
+
+```java
+@Inherited
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MyAnnotation {
+ String value();
+}
+
+@MyAnnotation("parent")
+public class Parent {
+}
+
+// Child会继承Parent的@MyAnnotation注解
+public class Child extends Parent {
+}
+```
+
+---
+
+## ✅ 今日检查清单
+
+- [ ] 理解了注解的概念和作用
+- [ ] 理解了元注解的含义
+- [ ] 创建了@DBRouter注解
+- [ ] 创建了@DBRouterStrategy注解
+- [ ] 理解了@Target和@Retention的作用
+- [ ] 完成了拓展阅读
+
+---
+
+## 🎯 明日预告
+
+明天我们将学习:
+- Java反射(Reflection)基础
+- 如何通过反射获取方法、字段
+- 如何通过反射调用方法和获取字段值
+
+---
+
+## 💡 思考题
+
+1. 为什么@DBRouter要用@Retention(RetentionPolicy.RUNTIME)?
+2. 如果@Target只写ElementType.METHOD,类上能用吗?
+3. 注解的属性可以是什么类型?
+
+---
+
+## 📚 参考资源
+
+- [Java注解官方文档](https://docs.oracle.com/javase/tutorial/java/annotations/)
+- [注解深入理解](https://www.baeldung.com/java-annotations-guide)
+- [反射和注解](https://www.baeldung.com/java-reflection)
diff --git "a/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25404\345\244\251-Java\345\217\215\345\260\204\345\237\272\347\241\200.md" "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25404\345\244\251-Java\345\217\215\345\260\204\345\237\272\347\241\200.md"
new file mode 100644
index 0000000000000000000000000000000000000000..a0d478ba4b45eff7aefa2941b43f4c8be33e89d4
--- /dev/null
+++ "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25404\345\244\251-Java\345\217\215\345\260\204\345\237\272\347\241\200.md"
@@ -0,0 +1,421 @@
+# 第04天:Java反射基础
+
+## 📚 今日目标
+
+1. 理解Java反射的概念
+2. 学会通过反射获取类、方法、字段信息
+3. 学会通过反射调用方法和获取字段值
+4. 实现PropertyUtil工具类
+
+---
+
+## 🎯 知识点1:什么是反射?
+
+### 生活中的例子
+
+**照镜子**:
+- 看到自己的样子(类的信息)
+- 看到自己穿什么衣服(字段)
+- 看到自己能做什么动作(方法)
+
+**Java反射**:
+- 在运行时获取类的信息
+- 获取类的字段、方法
+- 动态调用方法和访问字段
+
+### 为什么需要反射?
+
+**场景**:我们需要从方法参数中获取路由键的值
+
+```java
+@DBRouter(key = "userId")
+public void queryUser(User user) {
+ // 我们需要获取 user.getUserId() 的值
+ // 但不知道参数是什么类型,也不知道有哪些字段
+ // 怎么办?用反射!
+}
+```
+
+---
+
+## 🎯 知识点2:反射的核心类
+
+### Class类:类的元信息
+
+```java
+// 获取Class对象的三种方式
+Class> clazz1 = User.class; // 方式1:类字面量
+Class> clazz2 = user.getClass(); // 方式2:对象.getClass()
+Class> clazz3 = Class.forName("com.example.User"); // 方式3:类名
+
+// 获取类名
+String className = clazz.getName(); // 完整类名:com.example.User
+String simpleName = clazz.getSimpleName(); // 简单类名:User
+```
+
+### Method类:方法信息
+
+```java
+// 获取所有公共方法
+Method[] methods = clazz.getMethods();
+
+// 获取指定方法(包括私有方法)
+Method method = clazz.getDeclaredMethod("getUserId");
+
+// 获取方法名
+String methodName = method.getName();
+
+// 调用方法
+Object result = method.invoke(user); // 相当于 user.getUserId()
+```
+
+### Field类:字段信息
+
+```java
+// 获取所有字段(包括私有)
+Field[] fields = clazz.getDeclaredFields();
+
+// 获取指定字段
+Field field = clazz.getDeclaredField("userId");
+
+// 设置可访问(访问私有字段需要)
+field.setAccessible(true);
+
+// 获取字段值
+Object value = field.get(user); // 相当于 user.userId
+
+// 设置字段值
+field.set(user, 12345L); // 相当于 user.userId = 12345L
+```
+
+---
+
+## 🛠️ 实践任务1:通过反射获取属性值
+
+### 步骤1:创建PropertyUtil工具类
+
+在 `src/main/java/cn/bugstack/middleware/db/router/util/` 目录下创建 `PropertyUtil.java`:
+
+```java
+package cn.bugstack.middleware.db.router.util;
+
+import org.apache.commons.beanutils.PropertyUtils;
+import org.springframework.core.env.Environment;
+
+/**
+ * 属性工具类
+ * 用于通过反射获取对象属性值
+ *
+ * @author 小傅哥
+ */
+public class PropertyUtil {
+
+ private static int springBootVersion = 1;
+
+ static {
+ try {
+ // 检测Spring Boot版本
+ Class.forName("org.springframework.boot.bind.RelaxedPropertyResolver");
+ } catch (ClassNotFoundException e) {
+ springBootVersion = 2;
+ }
+ }
+
+ /**
+ * 处理Spring环境属性
+ *
+ * @param environment Spring环境
+ * @param prefix 属性前缀
+ * @param targetClass 目标类型
+ * @param 泛型
+ * @return 属性对象
+ */
+ public static T handle(Environment environment, String prefix, Class targetClass) {
+ try {
+ if (springBootVersion == 1) {
+ return (T) v1(environment, prefix);
+ } else {
+ return (T) v2(environment, prefix, targetClass);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("获取属性失败: " + prefix, e);
+ }
+ }
+
+ /**
+ * Spring Boot 1.x 版本
+ */
+ private static Object v1(Environment environment, String prefix) {
+ // Spring Boot 1.x 使用 RelaxedPropertyResolver
+ // 这里简化处理,实际项目中可能需要兼容
+ throw new UnsupportedOperationException("Spring Boot 1.x 暂不支持");
+ }
+
+ /**
+ * Spring Boot 2.x 版本
+ */
+ private static Object v2(Environment environment, String prefix, Class> targetClass) {
+ // Spring Boot 2.x 使用 Binder
+ try {
+ return org.springframework.boot.context.properties.bind.Binder
+ .get(environment)
+ .bind(prefix, targetClass)
+ .orElse(null);
+ } catch (Exception e) {
+ throw new RuntimeException("绑定属性失败: " + prefix, e);
+ }
+ }
+
+ /**
+ * 通过反射获取对象属性值
+ *
+ * @param obj 对象
+ * @param propertyName 属性名
+ * @return 属性值
+ */
+ public static Object getProperty(Object obj, String propertyName) {
+ try {
+ return PropertyUtils.getProperty(obj, propertyName);
+ } catch (Exception e) {
+ throw new RuntimeException("获取属性值失败: " + propertyName, e);
+ }
+ }
+
+ /**
+ * 通过反射设置对象属性值
+ *
+ * @param obj 对象
+ * @param propertyName 属性名
+ * @param value 属性值
+ */
+ public static void setProperty(Object obj, String propertyName, Object value) {
+ try {
+ PropertyUtils.setProperty(obj, propertyName, value);
+ } catch (Exception e) {
+ throw new RuntimeException("设置属性值失败: " + propertyName, e);
+ }
+ }
+}
+```
+
+### 代码解释
+
+1. **PropertyUtils.getProperty()**:使用Apache Commons BeanUtils获取属性值
+ - 支持嵌套属性:`user.address.city`
+ - 支持索引属性:`list[0]`
+ - 自动处理getter方法
+
+2. **Spring Boot版本检测**:不同版本的API不同,需要兼容处理
+
+3. **异常处理**:统一抛出RuntimeException,便于上层处理
+
+---
+
+## 🛠️ 实践任务2:手动实现属性获取(理解原理)
+
+### 步骤1:创建简化版PropertyUtil
+
+为了理解原理,我们手动实现一个简化版:
+
+```java
+package cn.bugstack.middleware.db.router.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * 属性工具类(手动实现版,用于理解原理)
+ */
+public class PropertyUtilManual {
+
+ /**
+ * 手动获取属性值(理解原理用)
+ *
+ * @param obj 对象
+ * @param propertyName 属性名
+ * @return 属性值
+ */
+ public static Object getPropertyManual(Object obj, String propertyName) {
+ if (obj == null || propertyName == null) {
+ return null;
+ }
+
+ Class> clazz = obj.getClass();
+
+ // 方式1:通过getter方法获取
+ try {
+ String getterName = "get" + capitalize(propertyName);
+ Method getter = clazz.getMethod(getterName);
+ return getter.invoke(obj);
+ } catch (Exception e) {
+ // getter方法不存在,尝试直接访问字段
+ }
+
+ // 方式2:直接访问字段
+ try {
+ Field field = clazz.getDeclaredField(propertyName);
+ field.setAccessible(true); // 允许访问私有字段
+ return field.get(obj);
+ } catch (Exception e) {
+ throw new RuntimeException("无法获取属性: " + propertyName, e);
+ }
+ }
+
+ /**
+ * 首字母大写
+ */
+ private static String capitalize(String str) {
+ if (str == null || str.length() == 0) {
+ return str;
+ }
+ return str.substring(0, 1).toUpperCase() + str.substring(1);
+ }
+}
+```
+
+### 使用示例
+
+```java
+public class User {
+ private Long userId;
+ private String name;
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+}
+
+// 使用
+User user = new User();
+user.setUserId(12345L);
+
+// 方式1:使用BeanUtils(推荐)
+Object value1 = PropertyUtil.getProperty(user, "userId"); // 12345L
+
+// 方式2:手动实现(理解原理)
+Object value2 = PropertyUtilManual.getPropertyManual(user, "userId"); // 12345L
+```
+
+---
+
+## 🎓 知识点拓展
+
+### 拓展1:反射的性能问题
+
+**问题**:反射比直接调用慢
+
+```java
+// 直接调用(快)
+user.getUserId();
+
+// 反射调用(慢,约慢10-100倍)
+Method method = User.class.getMethod("getUserId");
+method.invoke(user);
+```
+
+**优化方案**:
+1. **缓存Method对象**:不要每次都获取
+2. **使用MethodHandle**:Java 7+,性能更好
+3. **代码生成**:编译时生成代码
+
+**例子**:
+```java
+// 缓存Method对象
+private static final Method GET_USER_ID_METHOD;
+static {
+ try {
+ GET_USER_ID_METHOD = User.class.getMethod("getUserId");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+}
+
+// 使用时直接调用缓存的Method
+Object value = GET_USER_ID_METHOD.invoke(user);
+```
+
+### 拓展2:BeanUtils vs 手动反射
+
+**Apache Commons BeanUtils**:
+- ✅ 功能强大(支持嵌套属性、索引属性)
+- ✅ 代码简洁
+- ❌ 性能稍慢
+- ❌ 依赖外部库
+
+**手动反射**:
+- ✅ 性能稍好
+- ✅ 无外部依赖
+- ❌ 功能简单
+- ❌ 代码复杂
+
+**选择建议**:
+- 性能要求高:手动反射 + 缓存
+- 功能要求高:BeanUtils
+- 我们项目:使用BeanUtils(功能优先)
+
+### 拓展3:获取方法参数名
+
+**问题**:如何获取方法参数的真实名称?
+
+```java
+public void queryUser(Long userId, String name) {
+ // 如何知道第一个参数叫userId?
+}
+```
+
+**Java 8之前**:
+- 参数名会丢失(编译后变成arg0, arg1)
+- 需要编译时加 `-parameters` 参数
+
+**Java 8+**:
+```java
+// 编译时加参数:javac -parameters
+Method method = UserService.class.getMethod("queryUser", Long.class, String.class);
+Parameter[] parameters = method.getParameters();
+String paramName = parameters[0].getName(); // userId
+```
+
+**我们的项目**:
+- 不依赖参数名
+- 通过遍历参数对象,查找包含指定属性的对象
+- 更灵活,不依赖编译参数
+
+---
+
+## ✅ 今日检查清单
+
+- [ ] 理解了反射的概念和作用
+- [ ] 学会了通过反射获取类、方法、字段信息
+- [ ] 学会了通过反射调用方法和获取字段值
+- [ ] 实现了PropertyUtil工具类
+- [ ] 理解了BeanUtils的工作原理
+- [ ] 完成了拓展阅读
+
+---
+
+## 🎯 明日预告
+
+明天我们将学习:
+- Spring AOP基础
+- 切面、切点、通知的概念
+- 如何创建AOP切面
+
+---
+
+## 💡 思考题
+
+1. 为什么反射比直接调用慢?
+2. 如何优化反射的性能?
+3. 什么时候必须用反射,什么时候可以用其他方式?
+
+---
+
+## 📚 参考资源
+
+- [Java反射官方文档](https://docs.oracle.com/javase/tutorial/reflect/)
+- [反射性能优化](https://www.baeldung.com/java-reflection-performance)
+- [Apache Commons BeanUtils](https://commons.apache.org/proper/commons-beanutils/)
diff --git "a/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25405\345\244\251-Spring-AOP\345\237\272\347\241\200.md" "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25405\345\244\251-Spring-AOP\345\237\272\347\241\200.md"
new file mode 100644
index 0000000000000000000000000000000000000000..01929d0e5f4d983dd34d2da40577eb2763928bfa
--- /dev/null
+++ "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25405\345\244\251-Spring-AOP\345\237\272\347\241\200.md"
@@ -0,0 +1,319 @@
+# 第05天:Spring AOP基础
+
+## 📚 今日目标
+
+1. 理解AOP的概念和作用
+2. 理解切面、切点、通知的概念
+3. 学会创建AOP切面
+4. 理解@Around、@Before、@After等注解
+
+---
+
+## 🎯 知识点1:什么是AOP?
+
+### 生活中的例子
+
+**横切关注点**:
+- 日志记录:每个方法都要记录日志
+- 事务管理:每个方法都要开启/提交事务
+- 权限检查:每个方法都要检查权限
+
+**问题**:如果每个方法都写一遍,代码重复,维护困难
+
+**解决方案**:AOP(面向切面编程)
+- 把横切关注点提取出来
+- 在需要的地方自动应用
+- 不污染业务代码
+
+### AOP核心概念
+
+**切面(Aspect)**:横切关注点的模块化(如日志切面、事务切面)
+
+**切点(Pointcut)**:匹配哪些方法需要被拦截
+
+**通知(Advice)**:什么时候执行(Before、After、Around)
+
+**连接点(JoinPoint)**:方法执行的点
+
+---
+
+## 🎯 知识点2:AOP通知类型
+
+### @Before:前置通知
+
+```java
+@Before("execution(* com.example.service.*.*(..))")
+public void before(JoinPoint joinPoint) {
+ System.out.println("方法执行前");
+ // 可以获取方法参数
+ Object[] args = joinPoint.getArgs();
+}
+```
+
+### @After:后置通知
+
+```java
+@After("execution(* com.example.service.*.*(..))")
+public void after(JoinPoint joinPoint) {
+ System.out.println("方法执行后");
+}
+```
+
+### @Around:环绕通知(最重要)
+
+```java
+@Around("execution(* com.example.service.*.*(..))")
+public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
+ // 方法执行前
+ System.out.println("方法执行前");
+
+ // 执行原方法
+ Object result = joinPoint.proceed();
+
+ // 方法执行后
+ System.out.println("方法执行后");
+
+ return result;
+}
+```
+
+**为什么用@Around?**
+- 可以在方法执行前后都处理
+- 可以控制是否执行原方法
+- 可以修改返回值
+
+---
+
+## 🛠️ 实践任务:创建路由切面
+
+### 步骤1:创建DBRouterJoinPoint切面类
+
+在 `src/main/java/cn/bugstack/middleware/db/router/` 目录下创建 `DBRouterJoinPoint.java`:
+
+```java
+package cn.bugstack.middleware.db.router;
+
+import cn.bugstack.middleware.db.router.annotation.DBRouter;
+import cn.bugstack.middleware.db.router.config.DBRouterConfig;
+import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
+import cn.bugstack.middleware.db.router.util.PropertyUtil;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Method;
+
+/**
+ * 数据库路由切面
+ *
+ * 拦截带@DBRouter注解的方法,执行路由逻辑
+ *
+ * @author 小傅哥
+ */
+@Aspect
+public class DBRouterJoinPoint {
+
+ private Logger logger = LoggerFactory.getLogger(DBRouterJoinPoint.class);
+
+ private DBRouterConfig dbRouterConfig;
+ private IDBRouterStrategy dbRouterStrategy;
+
+ public DBRouterJoinPoint(DBRouterConfig dbRouterConfig, IDBRouterStrategy dbRouterStrategy) {
+ this.dbRouterConfig = dbRouterConfig;
+ this.dbRouterStrategy = dbRouterStrategy;
+ }
+
+ /**
+ * 定义切点:拦截所有带@DBRouter注解的方法
+ */
+ @Pointcut("@annotation(cn.bugstack.middleware.db.router.annotation.DBRouter)")
+ public void aopPoint() {
+ }
+
+ /**
+ * 环绕通知:在方法执行前后处理路由逻辑
+ */
+ @Around("aopPoint() && @annotation(dbRouter)")
+ public Object doRouter(ProceedingJoinPoint jp, DBRouter dbRouter) throws Throwable {
+ String dbKey = dbRouter.key();
+ if (null == dbKey || dbKey.isEmpty()) {
+ throw new RuntimeException("annotation DBRouter key is null!");
+ }
+
+ // 获取路由键的值
+ String dbKeyAttr = getAttrValue(dbKey, jp.getArgs());
+
+ // 执行路由
+ dbRouterStrategy.doRouter(dbKeyAttr);
+
+ // 执行原方法
+ try {
+ return jp.proceed();
+ } finally {
+ // 清理路由信息
+ dbRouterStrategy.clear();
+ }
+ }
+
+ /**
+ * 获取路由键的值
+ *
+ * @param attr 路由键字段名(如:userId)
+ * @param args 方法参数数组
+ * @return 路由键的值
+ */
+ public String getAttrValue(String attr, Object[] args) {
+ if (1 == args.length) {
+ // 只有一个参数,直接从这个参数获取
+ Object arg = args[0];
+ if (arg instanceof String) {
+ return arg.toString();
+ }
+ return String.valueOf(PropertyUtil.getProperty(arg, attr));
+ }
+
+ // 多个参数,遍历查找包含该属性的对象
+ for (Object arg : args) {
+ if (arg == null) {
+ continue;
+ }
+ try {
+ Object value = PropertyUtil.getProperty(arg, attr);
+ if (null != value) {
+ return String.valueOf(value);
+ }
+ } catch (Exception e) {
+ // 忽略,继续查找
+ }
+ }
+ throw new RuntimeException("未找到路由键: " + attr);
+ }
+
+ /**
+ * 获取方法对象
+ */
+ private Method getMethod(JoinPoint jp) throws NoSuchMethodException {
+ Signature sig = jp.getSignature();
+ MethodSignature methodSignature = (MethodSignature) sig;
+ return jp.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
+ }
+}
+```
+
+### 代码解释
+
+1. **@Aspect**:标识这是一个切面类
+
+2. **@Pointcut**:定义切点,匹配所有带@DBRouter注解的方法
+
+3. **@Around**:环绕通知,可以在方法执行前后处理
+
+4. **ProceedingJoinPoint**:
+ - `jp.getArgs()`:获取方法参数
+ - `jp.proceed()`:执行原方法
+
+5. **路由逻辑**:
+ - 获取路由键的值
+ - 执行路由(设置到ThreadLocal)
+ - 执行原方法
+ - 清理路由信息
+
+---
+
+## 🎓 知识点拓展
+
+### 拓展1:切点表达式
+
+**execution表达式**:
+```java
+// 匹配所有public方法
+execution(public * *(..))
+
+// 匹配指定包下的所有方法
+execution(* com.example.service.*.*(..))
+
+// 匹配指定类的所有方法
+execution(* com.example.service.UserService.*(..))
+
+// 匹配指定方法
+execution(* com.example.service.UserService.queryUser(..))
+```
+
+**@annotation表达式**:
+```java
+// 匹配所有带@DBRouter注解的方法
+@annotation(cn.bugstack.middleware.db.router.annotation.DBRouter)
+
+// 匹配所有带指定注解的方法,并获取注解对象
+@annotation(dbRouter)
+```
+
+**组合表达式**:
+```java
+// 使用 &&、||、! 组合
+@Pointcut("execution(* com.example.service.*.*(..)) && @annotation(DBRouter)")
+```
+
+### 拓展2:JoinPoint vs ProceedingJoinPoint
+
+**JoinPoint**:
+- 只能获取信息,不能控制执行
+- 用于@Before、@After
+
+**ProceedingJoinPoint**:
+- 继承自JoinPoint
+- 可以控制是否执行原方法
+- 用于@Around
+
+### 拓展3:AOP代理机制
+
+**JDK动态代理**:
+- 基于接口
+- 目标类必须实现接口
+
+**CGLIB代理**:
+- 基于继承
+- 不需要接口
+
+**Spring选择**:
+- 有接口:JDK动态代理
+- 无接口:CGLIB代理
+
+---
+
+## ✅ 今日检查清单
+
+- [ ] 理解了AOP的概念和作用
+- [ ] 理解了切面、切点、通知的概念
+- [ ] 创建了DBRouterJoinPoint切面类
+- [ ] 理解了@Around通知的使用
+- [ ] 理解了ProceedingJoinPoint的用法
+- [ ] 完成了拓展阅读
+
+---
+
+## 🎯 明日预告
+
+明天我们将学习:
+- Spring Boot自动配置原理
+- @Configuration和@Bean
+- spring.factories文件
+
+---
+
+## 💡 思考题
+
+1. 为什么用@Around而不是@Before+@After?
+2. 如何获取被拦截方法的返回值?
+3. AOP的代理机制是什么?
+
+---
+
+## 📚 参考资源
+
+- [Spring AOP官方文档](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop)
+- [AspectJ切点表达式](https://www.eclipse.org/aspectj/doc/released/adk15notebook/ataspectj-pcadvice.html)
+- [Spring AOP原理](https://www.baeldung.com/spring-aop)
diff --git "a/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25406\345\244\251-Spring-Boot\350\207\252\345\212\250\351\205\215\347\275\256\345\216\237\347\220\206.md" "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25406\345\244\251-Spring-Boot\350\207\252\345\212\250\351\205\215\347\275\256\345\216\237\347\220\206.md"
new file mode 100644
index 0000000000000000000000000000000000000000..0b182631785f441188ad95c8184a343901392682
--- /dev/null
+++ "b/30\345\244\251\345\256\236\347\216\260\346\214\207\345\215\227/\347\254\25406\345\244\251-Spring-Boot\350\207\252\345\212\250\351\205\215\347\275\256\345\216\237\347\220\206.md"
@@ -0,0 +1,330 @@
+# 第06天:Spring Boot自动配置原理
+
+## 📚 今日目标
+
+1. 理解Spring Boot自动配置的原理
+2. 理解@Configuration和@Bean
+3. 理解条件注解
+4. 创建spring.factories文件
+
+---
+
+## 🎯 知识点1:Spring Boot自动配置原理
+
+### 为什么需要自动配置?
+
+**问题**:每次使用框架都要手动配置很多Bean
+
+**解决方案**:Spring Boot自动配置
+- 检测classpath中的类
+- 自动创建Bean
+- 开箱即用
+
+### 自动配置的流程
+
+```
+1. Spring Boot启动
+ ↓
+2. 读取META-INF/spring.factories
+ ↓
+3. 加载自动配置类
+ ↓
+4. 根据条件注解判断是否生效
+ ↓
+5. 创建Bean
+```
+
+---
+
+## 🎯 知识点2:@Configuration和@Bean
+
+### @Configuration:配置类
+
+```java
+@Configuration
+public class MyConfig {
+
+ @Bean
+ public MyService myService() {
+ return new MyService();
+ }
+}
+```
+
+**作用**:标识这是一个配置类,Spring会扫描其中的@Bean方法
+
+### @Bean:创建Bean
+
+```java
+@Bean
+public DataSource dataSource() {
+ return new HikariDataSource();
+}
+```
+
+**作用**:方法返回的对象会被注册为Spring Bean
+
+---
+
+## 🎯 知识点3:条件注解
+
+### @ConditionalOnClass:类存在时生效
+
+```java
+@ConditionalOnClass(DataSource.class)
+public class DataSourceAutoConfig {
+ // 只有当classpath中存在DataSource类时才生效
+}
+```
+
+### @ConditionalOnMissingBean:Bean不存在时生效
+
+```java
+@Bean
+@ConditionalOnMissingBean
+public MyService myService() {
+ // 只有当容器中不存在MyService Bean时才创建
+ return new MyService();
+}
+```
+
+### @ConditionalOnProperty:属性存在时生效
+
+```java
+@ConditionalOnProperty(prefix = "db-router", name = "enabled", havingValue = "true")
+public class DBRouterAutoConfig {
+ // 只有当db-router.enabled=true时才生效
+}
+```
+
+---
+
+## 🛠️ 实践任务:创建自动配置类
+
+### 步骤1:创建DataSourceAutoConfig
+
+在 `src/main/java/cn/bugstack/middleware/db/router/config/` 目录下创建 `DataSourceAutoConfig.java`:
+
+```java
+package cn.bugstack.middleware.db.router.config;
+
+import cn.bugstack.middleware.db.router.DBRouterJoinPoint;
+import cn.bugstack.middleware.db.router.DBRouterConfig;
+import cn.bugstack.middleware.db.router.dynamic.DynamicDataSource;
+import cn.bugstack.middleware.db.router.dynamic.DynamicMybatisPlugin;
+import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
+import cn.bugstack.middleware.db.router.strategy.impl.DBRouterStrategyHashCode;
+import cn.bugstack.middleware.db.router.util.PropertyUtil;
+import org.apache.ibatis.plugin.Interceptor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 数据源自动配置类
+ *
+ * @author 小傅哥
+ */
+@Configuration
+@ConditionalOnClass({DataSource.class, org.apache.ibatis.session.SqlSessionFactory.class})
+@EnableConfigurationProperties(DBRouterConfig.class)
+public class DataSourceAutoConfig implements EnvironmentAware {
+
+ private static final String TAG_GLOBAL = "global";
+ private static final String TAG_POOL = "pool";
+
+ private Map> dataSourceMap = new HashMap<>();
+ private Map defaultDataSourceConfig;
+ private int dbCount;
+ private int tbCount;
+ private String routerKey;
+
+ /**
+ * 创建路由配置
+ */
+ @Bean
+ public DBRouterConfig dbRouterConfig() {
+ DBRouterConfig config = new DBRouterConfig();
+ config.setDbCount(dbCount);
+ config.setTbCount(tbCount);
+ config.setRouterKey(routerKey);
+ return config;
+ }
+
+ /**
+ * 创建路由策略
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public IDBRouterStrategy dbRouterStrategy(DBRouterConfig dbRouterConfig) {
+ return new DBRouterStrategyHashCode(dbRouterConfig);
+ }
+
+ /**
+ * 创建AOP切面
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public DBRouterJoinPoint point(DBRouterConfig dbRouterConfig, IDBRouterStrategy dbRouterStrategy) {
+ return new DBRouterJoinPoint(dbRouterConfig, dbRouterStrategy);
+ }
+
+ /**
+ * 创建MyBatis插件
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public Interceptor plugin() {
+ return new DynamicMybatisPlugin();
+ }
+
+ /**
+ * 创建动态数据源
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public DataSource createDataSource() {
+ // 创建多个数据源
+ Map