一、项目概述
boot-boost 是一个面向 Spring 框架高级特性的演练与验证项目,旨在系统性覆盖循环依赖与三级缓存、SpEL 表达式引擎、SpringFactoriesLoader 演进、父子容器隔离、原型 Bean 生命周期陷阱、外部化配置优先级以及Spring Boot 启动流程深度定制七大主题。项目通过设计可运行的 boot-boost-demo 模块,用实际代码验证这些知识点,并提供启动性能监控、规则引擎等可复用组件。
根据前三个实战项目的知识覆盖情况,本项目特别填补以下空白:
- LightORM(ORM 框架设计):未涉及容器启动流程与父子容器
- DynamicDS(多数据源动态路由):未涉及 SpEL 表达式计算与规则引擎
- BeanEye(Bean 生命周期监控):已监控生命周期,但未深入三级缓存、原型 Bean 泄漏、启动流程定制
因此,boot-boost 不仅是一个学习验证项目,更可作为一个 Spring Boot 启动诊断与扩展工具包 投入实际使用。
二、整体架构
2.1 模块划分
flowchart LR
subgraph boot-boost
direction TB
A[boot-boost-core] -->|基础能力| B[boot-boost-spring-boot-starter]
B -->|自动配置| C[boot-boost-demo]
end
A1[spel 规则引擎] --> A
A2[lifecycle 启动流程定制] --> A
A3[context 父子容器] --> A
A4[monitor 性能监控] --> A
B1[autoconfigure 自动配置] --> B
B2[initializer 初始化器] --> B
B3[listener 启动监听器] --> B
B4[resources/META-INF 注册文件] --> B
C1[循环依赖 Service] --> C
C2[SpEL 规则示例] --> C
C3[父子容器配置] --> C
C4[启动预热 Runner] --> C
- boot-boost-core:纯逻辑组件,不依赖 Spring Boot,仅依赖 Spring Framework,提供 SpEL 规则引擎、启动流程扩展点接口、父子容器工具、监控核心逻辑。
- boot-boost-spring-boot-starter:自动配置模块,负责将所有组件装配到 Spring Boot 应用中,同时提供
spring.factories与AutoConfiguration.imports两种注册方式,演示演进过程。 - boot-boost-demo:可运行的演示应用,内含所有验证场景的代码,通过 profile 切换不同实验。
2.2 启动流程序列图
sequenceDiagram
participant App as DemoApplication
participant Runner as SpringApplication
participant RL as SpringApplicationRunListener
participant Env as EnvironmentPostProcessor
participant Initializer as ApplicationContextInitializer
participant Container as ApplicationContext
participant BPP as BeanPostProcessor
participant AppRunner as ApplicationRunner
App->>Runner: run()
Runner->>Runner: 创建 SpringApplication
Runner->>RL: starting()
Runner->>Env: postProcessEnvironment()
Env-->>Runner: 添加自定义 PropertySource
Runner->>RL: environmentPrepared()
Runner->>Container: createApplicationContext()
Runner->>Initializer: initialize()
Initializer-->>Container: 注册额外 BeanDefinition
Runner->>RL: contextPrepared()
Runner->>Container: refresh()
Container->>BPP: 实例化 Bean,触发三级缓存
Runner->>RL: contextLoaded()
Runner->>RL: started()
Runner->>AppRunner: run()
AppRunner->>AppRunner: 预热缓存
Runner->>RL: running()
三、核心技术点设计与实现
3.1 循环依赖与三级缓存的验证
3.1.1 知识要点
- Spring 通过三级缓存解决单例 Bean 的设值循环依赖:
singletonObjects(一级):完全初始化好的 BeanearlySingletonObjects(二级):提早曝光的 Bean 引用(可能未完成属性填充)singletonFactories(三级):ObjectFactory,可生成代理对象的工厂
- 构造器注入无法解决循环依赖,因为此时对象尚未实例化,无法提前暴露引用。
@Lazy注解通过生成代理对象延迟注入,可破解构造器循环依赖,但会引入类型转换问题。- 原型作用域循环依赖无论何种注入方式均无法解决,因为原型 Bean 不进入缓存。
3.1.2 实现代码
ServiceA.java(构造器注入,无法启动)
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
ServiceB.java
@Service
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
预期:启动抛出 BeanCurrentlyInCreationException。
修改为设值注入(启动成功)
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
通过 BeanEye 风格监控三级缓存
自定义 BeanPostProcessor 结合反射获取 DefaultSingletonBeanRegistry 内部的缓存:
@Component
public class CacheMonitorBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
private DefaultListableBeanFactory beanFactory;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.beanFactory = (DefaultListableBeanFactory) ((GenericApplicationContext) applicationContext).getBeanFactory();
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("serviceA".equals(beanName) || "serviceB".equals(beanName)) {
logCacheState(beanName);
}
return bean;
}
private void logCacheState(String trigger) {
try {
Field singletonObjectsField = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
Field earlySingletonObjectsField = DefaultSingletonBeanRegistry.class.getDeclaredField("earlySingletonObjects");
Field singletonFactoriesField = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonFactories");
singletonObjectsField.setAccessible(true);
earlySingletonObjectsField.setAccessible(true);
singletonFactoriesField.setAccessible(true);
Map<String, Object> singletonObjects = (Map<String, Object>) singletonObjectsField.get(beanFactory);
Map<String, Object> earlySingletonObjects = (Map<String, Object>) earlySingletonObjectsField.get(beanFactory);
Map<String, ObjectFactory<?>> singletonFactories = (Map<String, ObjectFactory<?>>) singletonFactoriesField.get(beanFactory);
System.out.printf("[%s] 三级缓存状态: 一级=%s, 二级=%s, 三级=%s%n",
trigger, singletonObjects.keySet(), earlySingletonObjects.keySet(), singletonFactories.keySet());
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用 @Lazy 破解构造器循环依赖
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
此时 serviceB 是一个代理对象,类型为 ServiceB$$EnhancerBySpringCGLIB。需要注意类型转换时使用接口或合理设计。
循环依赖解决流程图:
flowchart TB
Start([创建 ServiceA]) --> A1{A的实例化}
A1 --> A2[将A的ObjectFactory加入三级缓存]
A2 --> A3[属性填充: 需要ServiceB]
A3 --> B1[创建 ServiceB]
B1 --> B2{实例化B}
B2 --> B3[将B的ObjectFactory加入三级缓存]
B3 --> B4[属性填充: 需要ServiceA]
B4 --> C1{从缓存获取A}
C1 --> C2[三级缓存有A的工厂]
C2 --> C3[调用工厂获取早期引用, 移入二级缓存]
C3 --> C4[注入A的早期引用到B]
C4 --> B5[完成B的初始化, 移入一级缓存]
B5 --> A4[注入完整的B到A]
A4 --> A5[完成A的初始化, 移入一级缓存]
A5 --> End([结束])
3.2 SpEL 表达式规则引擎
3.2.1 核心组件设计
@RuleExpression 注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RuleExpression {
String value(); // SpEL 表达式
}
SpelRuleEngine 接口与实现
public interface SpelRuleEngine {
<T> T evaluate(String expression, Object rootObject, Map<String, Object> variables, Class<T> returnType);
boolean evaluateAsBoolean(String expression, Map<String, Object> variables);
void addCachedExpression(String key, String expression);
}
@Component
public class DefaultSpelRuleEngine implements SpelRuleEngine {
private final SpelExpressionParser parser = new SpelExpressionParser();
private final Map<String, Expression> expressionCache = new ConcurrentHashMap<>();
private final EvaluationContext customContext; // 可通过配置选择 Simple 或 Standard
public DefaultSpelRuleEngine(@Value("${boot-boost.spel.evaluation-context:simple}") String contextType) {
if ("simple".equals(contextType)) {
this.customContext = SimpleEvaluationContext.forReadOnlyDataBinding().build();
} else {
this.customContext = new StandardEvaluationContext();
}
}
@Override
public <T> T evaluate(String expressionStr, Object rootObject, Map<String, Object> variables, Class<T> returnType) {
Expression expression = expressionCache.computeIfAbsent(expressionStr, parser::parseExpression);
EvaluationContext context = createContext(rootObject, variables);
return expression.getValue(context, returnType);
}
private EvaluationContext createContext(Object rootObject, Map<String, Object> variables) {
EvaluationContext context = (this.customContext instanceof StandardEvaluationContext)
? new StandardEvaluationContext(rootObject) : SimpleEvaluationContext.forReadOnlyDataBinding().withRootObject(rootObject).build();
if (variables != null) {
variables.forEach(context::setVariable);
}
return context;
}
}
安全防护对比
StandardEvaluationContext:允许类型引用、方法调用、构造器调用,存在注入风险(如T(java.lang.Runtime).exec('calc'))。SimpleEvaluationContext:仅允许属性访问和只读操作,禁止类型引用,从根源杜绝代码注入。
@ConditionalOnExpression 简化版实现
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnSpelExpressionCondition.class)
public @interface ConditionalOnSpEL {
String value();
}
public class OnSpelExpressionCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attrs = metadata.getAnnotationAttributes(ConditionalOnSpEL.class.getName());
String expression = (String) attrs.get("value");
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
StandardEvaluationContext evalContext = new StandardEvaluationContext();
evalContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
ExpressionParser parser = new SpelExpressionParser();
return Boolean.TRUE.equals(parser.parseExpression(expression).getValue(evalContext, Boolean.class));
}
}
SpEL 表达式解析流程
flowchart TD
A[规则字符串] --> B{缓存命中?}
B -- 是 --> C[获取已解析Expression]
B -- 否 --> D[SpelExpressionParser解析]
D --> E[生成Expression对象]
E --> C
C --> F[创建EvaluationContext]
F --> G[注册BeanResolver和变量]
G --> H[执行getValue]
H --> I[返回结果]
3.3 SpringFactoriesLoader 与 AutoConfiguration.imports 的演进对比
3.3.1 传统方式与新版方式
传统方式(spring.factories)
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.bootboost.autoconfigure.BootBoostAutoConfiguration
- 加载类:
SpringFactoriesLoader - 文件路径:
META-INF/spring.factories - 始于 Spring 3.2,多种扩展点共用一个文件,语义不清晰,且每次加载该文件都会实例化所有工厂类,存在性能开销。
新版方式(AutoConfiguration.imports)
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.bootboost.autoconfigure.BootBoostAutoConfiguration
- 由
ImportCandidates.load()加载,Spring Boot 2.7 引入 - 文件专用于自动配置,语义清晰,配合新的
@AutoConfiguration注解 - 加载性能更好,按需加载,支持条件过滤
BootBoostAutoConfiguration 示例
@AutoConfiguration
@ConditionalOnSpEL("${boot-boost.enabled:true}")
@EnableConfigurationProperties(BootBoostProperties.class)
public class BootBoostAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SpelRuleEngine spelRuleEngine(BootBoostProperties properties) {
return new DefaultSpelRuleEngine(properties.getSpel().getEvaluationContext());
}
@Bean
public StartupApplicationListener startupApplicationListener() {
return new StartupApplicationListener();
}
}
对比实验设计:
在启动类同时使用两种注册方式,通过 BeanPostProcessor 或 ApplicationListener 记录加载顺序日志,验证新版导入先于传统 spring.factories 被解析。
| 特性 | spring.factories | AutoConfiguration.imports |
|---|---|---|
| 文件位置 | META-INF/spring.factories | META-INF/spring/...imports |
| 加载时机 | Spring Boot 构建启动时完整扫描 | 自动配置专用阶段 |
| 语义清晰度 | 混合多个扩展点,不易维护 | 专用于自动配置 |
| 性能 | 全量加载,可能实例化无用类 | 按需加载,结合条件过滤 |
| 引入版本 | Spring 3.2+ / Boot 1.0+ | Boot 2.7+ |
3.4 父子容器与模块隔离
设计父子容器结构模拟 Spring MVC 的 Root WebApplicationContext 与 Servlet WebApplicationContext 模型。
父容器配置(基础设施)
@Configuration
@ComponentScan(basePackages = "com.example.demo.shared")
public class ParentContainerConfig {
@Bean
public DataSource dataSource() {
// H2 内存数据库
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
子容器配置(业务模块)
@Configuration
@ComponentScan(basePackages = "com.example.demo.module")
public class ChildContainerConfig {
// 模块特有的Bean
@Autowired
private DataSource dataSource; // 从父容器获取
}
演示代码
public class ParentChildContainerTest {
public static void main(String[] args) {
// 创建父容器
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(ParentContainerConfig.class);
// 创建子容器并设置父容器
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
child.setParent(parent);
child.register(ChildContainerConfig.class);
child.refresh();
// 子容器可访问父容器的Bean
DataSource ds = child.getBean(DataSource.class);
System.out.println("从子容器获取DataSource成功: " + ds);
// 父容器无法访问子容器的Bean
try {
parent.getBean(UserService.class);
} catch (NoSuchBeanDefinitionException e) {
System.out.println("父容器无法获取UserService: " + e.getMessage());
}
}
}
交互图
flowchart BT
subgraph 子容器
Controller
UserService
end
subgraph 父容器
DataSource
TransactionManager
end
Controller -->|调用| UserService
UserService -->|注入| DataSource
TransactionManager -->|注入| DataSource
3.5 原型 Bean 循环依赖与资源泄漏
3.5.1 原型循环依赖验证
@Component
@Scope("prototype")
public class PrototypeA {
@Autowired
private PrototypeB prototypeB;
}
@Component
@Scope("prototype")
public class PrototypeB {
@Autowired
private PrototypeA prototypeA;
}
// 每次调用 context.getBean(PrototypeA.class) 都会抛出 BeanCurrentlyInCreationException
原因:原型 Bean 不进入三级缓存,每次获取都重新创建,相互依赖导致无限循环。
3.5.2 资源泄漏模拟与处理
原型 Bean 持有资源:
@Component
@Scope("prototype")
public class LeakyResourceBean implements DisposableBean {
private final InputStream stream;
public LeakyResourceBean() throws FileNotFoundException {
this.stream = new FileInputStream("example.txt");
}
@Override
public void destroy() throws Exception {
stream.close(); // Spring不会自动调用原型Bean的destroy
System.out.println("资源已释放");
}
}
自定义 DestructionAwareBeanPostProcessor 手动管理
@Component
public class PrototypeDestructionPostProcessor extends DestructionAwareBeanPostProcessorAdapter {
private final Map<String, List<DisposableBean>> disposableBeans = new ConcurrentHashMap<>();
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
// 仅对原型Bean处理
}
@Override
public boolean requiresDestruction(Object bean) {
return bean instanceof DisposableBean;
}
// 在合适的时机调用 destroy,例如通过 @PreDestroy 自定义作用域或手动注册
}
更佳实践:使用 CustomScopeConfigurer 注册一个可管理销毁的自定义作用域,或由调用方显式调用 destroy。
3.6 @Value 与 @ConfigurationProperties 的优先级对比
AppProperties
@ConfigurationProperties(prefix = "app")
@Validated
public class AppProperties {
@NotNull
private String name;
private String version;
@Min(1)
private int maxRetry;
// getters/setters
}
对比验证类
@RestController
@RequestMapping("/config")
public class ConfigComparisonController {
@Value("${app.name}")
private String nameFromValue;
@Autowired
private AppProperties appProperties;
@GetMapping("/compare")
public Map<String, Object> compare() {
Map<String, Object> result = new HashMap<>();
result.put("valueAnnotation", nameFromValue);
result.put("configurationProperties", appProperties.getName());
result.put("maxRetry", appProperties.getMaxRetry());
return result;
}
}
验证场景:
- 通过
application.yml设置app.name,两者一致。 - 通过命令行参数
--app.name=cmd-value覆盖,两者均更新(这是同一套Environment,最终值一致)。 - 松散绑定:
@Value需要使用精确的app.name,而@ConfigurationProperties支持appName、app-name、APP_NAME等。可通过环境变量测试差异。 - 校验:
@ConfigurationProperties+@Validated可校验属性值,@Value不支持 JSR-303 校验。 - 默认值:
@Value("${app.timeout:5000}")提供默认值,@ConfigurationProperties则依靠字段默认值,属性缺失时保留字段初始值。
优先级链(外部化配置):
- 命令行参数
- JNDI 属性
- System.getProperties()
- 操作系统环境变量
- application-profile.yml
- application.yml
- @PropertySource
- SpringApplication.setDefaultProperties
3.7 Spring Boot 启动流程深度定制
3.7.1 ApplicationContextInitializer
public class CustomApplicationContextInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
@Override
public void initialize(GenericApplicationContext applicationContext) {
// 注册额外Bean,比如程序化添加数据源代理
applicationContext.registerBean("customizedBean", CustomizedBean.class);
System.out.println("[Initializer] 容器初始化完成,已注册 customizedBean");
}
}
注册在 META-INF/spring.factories:
org.springframework.context.ApplicationContextInitializer=\
com.bootboost.initializer.CustomApplicationContextInitializer
3.7.2 SpringApplicationRunListener
public class StartupApplicationListener implements SpringApplicationRunListener {
private final SpringApplication application;
private final String[] args;
private long startTime;
// 必须有此构造器
public StartupApplicationListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
startTime = System.currentTimeMillis();
System.out.println("=== 启动开始 ===");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
long cost = System.currentTimeMillis() - startTime;
System.out.println("环境准备完成,耗时: " + cost + "ms");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
long cost = System.currentTimeMillis() - startTime;
System.out.println("上下文准备完成,耗时: " + cost + "ms");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
long cost = System.currentTimeMillis() - startTime;
System.out.println("上下文加载完成(Bean定义加载完成),耗时: " + cost + "ms");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("应用已启动,总耗时: " + timeTaken.toMillis() + "ms");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("应用运行中...");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("启动失败: " + exception.getMessage());
}
}
注册同样在 spring.factories。
3.7.3 EnvironmentPostProcessor
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Map<String, Object> remoteProperties = Map.of("remote.config.name", "from-remote-center");
environment.getPropertySources().addFirst(new MapPropertySource("remoteConfig", remoteProperties));
System.out.println("[EnvironmentPostProcessor] 已添加远程配置源");
}
}
3.7.4 FailureAnalyzer
public class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {
return new FailureAnalysis(
"端口 " + cause.getPort() + " 已被占用",
"请检查端口占用情况或修改 server.port 配置",
cause
);
}
}
3.8 启动性能监控与诊断
StartupMonitor:利用 StartupApplicationListener 收集阶段耗时并暴露 Actuator 端点。
@Endpoint(id = "startup")
@Component
public class StartupMetricsEndpoint {
private final StartupApplicationListener listener;
@Autowired
public StartupMetricsEndpoint(StartupApplicationListener listener) {
this.listener = listener;
}
@ReadOperation
public Map<String, Object> startupReport() {
Map<String, Object> report = new LinkedHashMap<>();
report.put("stages", listener.getStageDurations()); // 各阶段耗时
report.put("slowBeans", getSlowBeans());
return report;
}
private List<String> getSlowBeans() {
// 从 BeanPostProcessor 收集的初始化耗时数据中筛选超过阈值的Bean
return SlowBeanDetector.getSlowBeans();
}
}
慢 Bean 检测:
@Component
public class SlowBeanDetector implements BeanPostProcessor {
private static final Map<String, Long> beanInitTimes = new ConcurrentHashMap<>();
private static long threshold = 500; // ms
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 在 Before 记录时间,After 计算耗时,此处简化逻辑
return bean;
}
}
启动预热:
@Component
public class CacheWarmUpRunner implements ApplicationRunner {
@Autowired
private SpelRuleEngine ruleEngine;
@Override
public void run(ApplicationArguments args) {
ruleEngine.addCachedExpression("vipCheck", "#{#user.isVip(#userId)}");
// 预编译热点表达式
System.out.println("SpEL 表达式预编译完成,启动预热结束");
}
}
四、boot-boost-demo 完整测试项目
4.1 项目结构
boot-boost-demo
├── src/main/java/com/example/demo
│ ├── DemoApplication.java
│ ├── service
│ │ ├── ServiceA.java
│ │ ├── ServiceB.java
│ │ ├── PrototypeA.java
│ │ └── PrototypeB.java
│ ├── spel
│ │ ├── RuleExpressionEvaluator.java
│ │ ├── SpelRuleEngine.java
│ │ └── VipDiscountRule.java
│ ├── config
│ │ ├── AppProperties.java
│ │ ├── ParentContainerConfig.java
│ │ └── ChildContainerConfig.java
│ ├── initializer
│ │ └── CustomApplicationContextInitializer.java
│ ├── listener
│ │ └── CustomSpringApplicationRunListener.java
│ └── runner
│ └── CacheWarmUpRunner.java
├── src/main/resources
│ ├── application.yml
│ └── META-INF
│ ├── spring.factories
│ └── spring
│ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
└── src/test/java/com/example/demo
├── CircularDependencyTest.java
├── SpelRuleEngineTest.java
├── ParentChildContainerTest.java
└── PrototypeLeakTest.java
4.2 application.yml 配置示例
boot-boost:
enabled: true
spel:
cache-expressions: true
evaluation-context: simple
startup:
warm-up-enabled: true
slow-bean-threshold: 500ms
app:
name: boot-boost-demo
version: 1.0.0
max-retry: 3
4.3 测试验证场景与预期
| 测试类 | 验证点 | 预期结果 |
|---|---|---|
| CircularDependencyTest | 构造器注入循环依赖 | 启动失败,抛出 BeanCurrentlyInCreationException |
| CircularDependencyTest | 设值注入循环依赖 | 启动成功,通过监控端点查看三级缓存变动 |
| SpelRuleEngineTest | VIP 用户规则执行 | #{@userService.isVip(#userId)} 返回 true |
| SpelRuleEngineTest | SimpleEvaluationContext 安全性 | 执行 T(java.lang.Runtime).exec('calc') 抛出异常 |
| ParentChildContainerTest | 父子容器隔离 | 子容器可获取父 Bean,父容器无法获取子 Bean |
| PrototypeLeakTest | 原型循环依赖 | 多次获取抛出异常,资源未自动释放 |
| ConfigComparisonController | 属性优先级与松散绑定 | @Value 不支持松散绑定,@ConfigurationProperties 支持校验 |
五、与 Spring 核心系列文章知识关联表
| 文章编号/主题 | boot-boost 中对应实现 | 知识点链接 |
|---|---|---|
| 第1篇 IoC容器 | 父子容器结构 | HierarchicalBeanFactory、容器隔离 |
| 第2篇 Bean生命周期 | SlowBeanDetector、原型Bean销毁 | BeanPostProcessor、DisposableBean |
| 第3篇 依赖注入 | ServiceA/ServiceB 设值注入 | @Autowired、@Lazy |
| 第4篇 AOP | @Lazy 生成代理对象对类型影响 | 代理与类型转换 |
| 第5篇 循环依赖终极剖析 | 三级缓存监控、构造器/设值对比 | 三级缓存流转、ObjectFactory |
| 第6篇 @Import机制 | @AutoConfiguration 新注解 | ImportSelector 与自动配置 |
| 第7篇 SpEL及其在框架中的妙用 | RuleExpressionEvaluator、SpelRuleEngine | SpelExpressionParser、EvaluationContext |
| 第8篇 容器扩展点 | ApplicationContextInitializer、BeanFactoryPostProcessor 使用 | 扩展点回调顺序 |
| 第9篇 SpringFactoriesLoader到AutoConfiguration.imports | 双注册方式对比实验 | 文件加载机制演进 |
| 第10篇 类型转换 | @Lazy 代理对象对转换影响 | ConversionService |
| 第11篇 Spring MVC 启动全景:父子容器 | 父子容器设计与实验 | 父子容器交互 |
| 第12篇 设计模式 | 规则引擎的模板模式 | 策略模式、模板方法 |
| 第13篇 反模式与排查宝典 | 原型泄漏、循环依赖排查 | BeanCurrentlyInCreationException 分析 |
| 第14篇 Spring Boot 启动流程 | CustomSpringApplicationRunListener、启动预热 | 启动阶段分解 |
| 第15篇 自动配置原理 | BootBoostAutoConfiguration、条件装配 | @Conditional、AutoConfiguration |
| 第16篇 MyBatis整合原理 | (本文不涉及,前三项目已覆盖) |
六、总结与展望
boot-boost 项目通过七大主题的深度演练,填补了 LightORM、DynamicDS、BeanEye 三个项目未覆盖的 Spring 核心高级特性。该项目不仅可用于学习和面试准备,其性能监控、规则引擎、启动诊断等组件更具备生产级落地的可能性。
本项目的后续演进方向包括:
- 将 SpEL 规则引擎扩展为支持数据库持久化与热更新。
- 将启动性能监控数据接入 Micrometer 与 Prometheus。
- 开发 IDEA 插件,可视化展示三级缓存变化和启动耗时火焰图。
- 与 BeanEye 合并,形成完整的 Spring 生命周期可观测性套件。 。