一、项目概述
boot-boost 是一个面向 Spring 框架高级特性的演练与验证项目,旨在系统性覆盖循环依赖与三级缓存 、SpEL 表达式引擎 、SpringFactoriesLoader 演进 、父子容器隔离 、原型 Bean 生命周期陷阱 、外部化配置优先级 以及Spring Boot 启动流程深度定制 七大主题。项目通过设计可运行的 boot-boost-demo 模块,用实际代码验证这些知识点,并提供启动性能监控、规则引擎等可复用组件。
根据前三个实战项目的知识覆盖情况,本项目特别填补以下空白:
- LightORM(ORM 框架设计):未涉及容器启动流程与父子容器
- DynamicDS(多数据源动态路由):未涉及 SpEL 表达式计算与规则引擎
- BeanEye(Bean 生命周期监控):已监控生命周期,但未深入三级缓存、原型 Bean 泄漏、启动流程定制
因此,boot-boost 不仅是一个学习验证项目,更可作为一个 Spring Boot 启动诊断与扩展工具包 投入实际使用。
二、整体架构
2.1 模块划分
- 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 启动流程序列图
三、核心技术点设计与实现
3.1 循环依赖与三级缓存的验证
3.1.1 知识要点
- Spring 通过三级缓存 解决单例 Bean 的设值循环依赖:
singletonObjects(一级):完全初始化好的 BeanearlySingletonObjects(二级):提早曝光的 Bean 引用(可能未完成属性填充)singletonFactories(三级):ObjectFactory,可生成代理对象的工厂
- 构造器注入无法解决循环依赖,因为此时对象尚未实例化,无法提前暴露引用。
@Lazy注解通过生成代理对象延迟注入,可破解构造器循环依赖,但会引入类型转换问题。- 原型作用域循环依赖无论何种注入方式均无法解决,因为原型 Bean 不进入缓存。
3.1.2 实现代码
ServiceA.java(构造器注入,无法启动)
java
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
ServiceB.java
java
@Service
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
预期 :启动抛出 BeanCurrentlyInCreationException。
修改为设值注入(启动成功)
java
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
通过 BeanEye 风格监控三级缓存
自定义 BeanPostProcessor 结合反射获取 DefaultSingletonBeanRegistry 内部的缓存:
java
@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 破解构造器循环依赖
java
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
此时 serviceB 是一个代理对象,类型为 ServiceB$$EnhancerBySpringCGLIB。需要注意类型转换时使用接口或合理设计。
循环依赖解决流程图:
3.2 SpEL 表达式规则引擎
3.2.1 核心组件设计
@RuleExpression 注解
java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RuleExpression {
String value(); // SpEL 表达式
}
SpelRuleEngine 接口与实现
java
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 简化版实现
java
@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 表达式解析流程
3.3 SpringFactoriesLoader 与 AutoConfiguration.imports 的演进对比
3.3.1 传统方式与新版方式
传统方式(spring.factories)
properties
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.bootboost.autoconfigure.BootBoostAutoConfiguration
- 加载类:
SpringFactoriesLoader - 文件路径:
META-INF/spring.factories - 始于 Spring 3.2,多种扩展点共用一个文件,语义不清晰,且每次加载该文件都会实例化所有工厂类,存在性能开销。
新版方式(AutoConfiguration.imports)
shell
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.bootboost.autoconfigure.BootBoostAutoConfiguration
- 由
ImportCandidates.load()加载,Spring Boot 2.7 引入 - 文件专用于自动配置,语义清晰,配合新的
@AutoConfiguration注解 - 加载性能更好,按需加载,支持条件过滤
BootBoostAutoConfiguration 示例
java
@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 模型。
父容器配置(基础设施)
java
@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);
}
}
子容器配置(业务模块)
java
@Configuration
@ComponentScan(basePackages = "com.example.demo.module")
public class ChildContainerConfig {
// 模块特有的Bean
@Autowired
private DataSource dataSource; // 从父容器获取
}
演示代码
java
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());
}
}
}
交互图
3.5 原型 Bean 循环依赖与资源泄漏
3.5.1 原型循环依赖验证
java
@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 持有资源:
java
@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 手动管理
java
@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
java
@ConfigurationProperties(prefix = "app")
@Validated
public class AppProperties {
@NotNull
private String name;
private String version;
@Min(1)
private int maxRetry;
// getters/setters
}
对比验证类
java
@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
java
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:
properties
org.springframework.context.ApplicationContextInitializer=\
com.bootboost.initializer.CustomApplicationContextInitializer
3.7.2 SpringApplicationRunListener
java
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
java
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
java
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 端点。
java
@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 检测:
java
@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;
}
}
启动预热:
java
@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 项目结构
css
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 配置示例
yaml
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 生命周期可观测性套件。 。