欢迎光临
我们一直在努力

自研 CodeStats 框架:与 Spring Framework、Spring Boot 启动流程的深度解析

一个从零打造的全栈 Java 框架,如何在没有 Spring 的情况下实现 IoC、MVC、嵌入式 Tomcat 和 MyBatis 风格 Mapper?本文带你深入剖析自研 CodeStats 的核心设计思想,并与 Spring 传统启动、Spring Boot 自动配置进行对比,看清框架演进的脉络。CodeStats 不仅是技术练习,更是 WWAIC 范式的首个实证项目。


📦 项目地址与资源

  • Gitee 开源仓库:https://gitee.com/zhouzuoli/code-stats.git

  • CSDN 系列文章:

    • 项目总览与核心代码分析

    • WWAIC 范式概念定义

    • WWAIC 实战:从零手写 HTTP 服务器到全栈 Java 框架

  • WWAIC 范式说明:WWAIC(Whole-Week AI Engineering,全周项目 AI 工程)指开发者在一周内将项目完整上下文提交给 AI,由 AI 直接生成一个可运行的完整系统。CodeStats 是这一范式的首个实证项目——100% 由 AI 生成,耗时仅一周,实现了从 IoC 容器到嵌入式 Tomcat 的全栈能力。


一、引言:为什么要自己写一个 Spring?

在 Java 后端开发中,Spring 生态已然成为事实标准。然而,当我们亲手实现一个微型 Spring + Tomcat 时,才能真正理解 IoC 容器如何管理 Bean、DispatcherServlet 如何分发请求、连接池如何限流。CodeStats 正是一个完全自研的“类 Spring”框架,它集成了 IoC 容器、MVC 架构、嵌入式 Tomcat、JDBC 连接池、MyBatis 风格 Mapper 以及代码分析引擎。本文将通过 启动流程 这个核心视角,对比 CodeStats 自研框架与 Spring Framework(传统 XML/注解驱动)以及 Spring Boot(自动配置 + 内嵌服务器)的差异,揭示框架设计的本质。


二、自研 CodeStats 启动流程深度解剖

2.1 入口:Bootstrap.main()

java

// Bootstrap.java
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
}

SpringApplication.run 是自研的“启动器”,它做了三件事:

  • 创建 AnnotationConfigApplicationContext,扫描指定包下的 @Controller、@Service、@Component 等注解,完成 IoC 容器的初始化。

  • 启动自研的 Catalina(嵌入式 Tomcat 实现),绑定端口(默认 28080)。

  • 注册关闭钩子,优雅停机。

  • 2.2 IoC 容器核心:AnnotationConfigApplicationContext

    自研的 AbstractApplicationContext 实现了经典的 refresh() 模板方法:

    java

    // AbstractApplicationContext.java
    public void refresh() throws Exception {
    prepareRefresh();
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    prepareBeanFactory(beanFactory);
    invokeBeanFactoryPostProcessors(beanFactory);
    registerBeanPostProcessors(beanFactory);
    initMessageSource();
    initApplicationEventMulticaster();
    onRefresh(); // 子类扩展点
    registerListeners();
    finishBeanFactoryInitialization(beanFactory); // 实例化所有非懒加载单例
    finishRefresh();
    }

    关键差异:自研版本没有 BeanDefinition 的完整注册后处理机制,但是实现了核心的 包扫描 → BeanDefinition 注册 → 单例创建 → 依赖注入 流程。尤其值得一提的是 @Autowired 解析支持了 @Qualifier 和 @Primary 的多候选 Bean 处理:

    java

    // AbstractAutowireCapableBeanFactory.java
    protected Object resolveDependency(Field field, Object bean) throws Exception {
    Map<String, ?> candidates = this.getBeansOfType(requiredType);
    if (candidates.size() == 1) return candidates.values().iterator().next();
    // 按 @Qualifier 或字段名匹配,再找 @Primary

    }

    2.3 嵌入式 Tomcat 容器:Catalina 与 Connector

    自研 Tomcat 采用经典的 Server → Service → Connector → Engine → Host → Context → Wrapper 层次结构,每个组件都实现了 Lifecycle 接口(init/start/stop/destroy)。启动时:

    java

    // Catalina.java
    public void start() {
    server.init();
    server.start();
    }

    Connector 使用 ServerSocket 监听端口,接收请求后封装为 Request 和 Response,经过 Pipeline-Valve 责任链,最终由 DispatcherServlet 处理。

    亮点:

    • 自研 WebappClassLoader 实现了类隔离,每个 Context 拥有独立的类加载器。

    • MultipartResolver 支持文件上传,通过 BoundaryFinder 高效解析 multipart 边界。

    • 完全手写的 DispatcherServlet 支持 @RequestMapping、@ResponseBody、@PathVariable、@RequestParam、@RequestBody 等核心注解。

    2.4 数据访问层:@Mapper 代理 + JdbcTemplate

    java

    // MapperProxy.java
    public Object invoke(Object proxy, Method method, Object[] args) {
    String sql = extractSqlFromAnnotation(method);
    SqlParser.ParsedSql parsed = SqlParser.parse(sql);
    // 根据返回值类型(List<T> / T / int)自动执行查询或更新
    if (returnType == List.class) {
    return jdbcTemplate.queryForList(parsedSql, elementType, paramValues);
    } else if (isSimpleType(returnType)) {
    return jdbcTemplate.queryOne(…);
    }
    }

    这实际上是 MyBatis 风格的声明式 DAO,仅通过 @Select 注解和 @Param 即可生成 SQL 代理,无需 XML。配合自研的 JdbcTemplate 和 SimpleDataSource 连接池(基于 Semaphore 限流 + 空闲队列),实现了完整的数据访问能力。

    2.5 启动时序图(自研 CodeStats)

    text

    Bootstrap.main()
    └─ SpringApplication.run()
    ├─ new AnnotationConfigApplicationContext(package)
    │ ├─ refreshBeanFactory() → 扫描类 → 注册 BeanDefinition
    │ ├─ registerMappers() → 为 @Mapper 接口创建动态代理并放入单例池
    │ └─ finishBeanFactoryInitialization() → 实例化单例 → 依赖注入
    └─ new Catalina()
    ├─ load() → 构造 Server/Service/Connector/Engine/Host/Context/Wrapper
    └─ start() → 启动 Connector 线程,监听端口


    三、Spring Framework 传统启动流程回顾

    以经典的 AnnotationConfigApplicationContext 为例(非 Spring Boot):

    java

    AnnotationConfigApplicationContext ctx =
    new AnnotationConfigApplicationContext(AppConfig.class);

    其 refresh() 方法实现与自研版本非常相似,但 Spring 做了更多精细化工作:

    步骤自研 CodeStatsSpring Framework
    BeanDefinition 注册 仅支持类名扫描,无条件注解 支持 @Conditional、@Import、FactoryBean
    依赖注入 字段注入(@Autowired) 构造器注入、字段注入、方法注入
    BeanPostProcessor 简单的前置/后置处理 内置几十个处理器(AOP、InitDestroy等)
    事件机制 无(预留空方法) 完整的事件发布/监听模型
    作用域 仅 singleton,无 prototype 完整支持 request/session/application
    容器扩展点 极少 BeanFactoryPostProcessor 广泛应用

    Spring 的 BeanFactoryPostProcessor 机制允许在 Bean 实例化之前修改 BeanDefinition,这是自研框架缺失的关键扩展能力。此外,Spring 通过 InstantiationAwareBeanPostProcessor 支持属性注入前的自定义逻辑,而自研版仅在 populateBean 中硬编码处理 @Autowired。


    四、Spring Boot 启动流程:颠覆性变化

    Spring Boot 的核心是 SpringApplication.run(),它做了 自动配置 + 嵌入式服务器:

    java

    @SpringBootApplication
    public class MyApp {
    public static void main(String[] args) {
    SpringApplication.run(MyApp.class, args);
    }
    }

    启动流程大致为:

  • 推断 Web 应用类型(Servlet/Reactive)。

  • 加载 META-INF/spring.factories 中的 ApplicationContextInitializer 和 ApplicationListener。

  • 创建 ConfigurableApplicationContext(如 AnnotationConfigServletWebServerApplicationContext)。

  • 调用 refresh() 前,通过 ServletWebServerApplicationContext 的 createWebServer() 创建内嵌的 Tomcat/Jetty/Undertow。

  • 执行 refresh() 完成 IoC 容器初始化。

  • 启动 Web Server。

  • 对比自研 CodeStats:

    特性自研 CodeStatsSpring Boot
    服务器创建时机 在 IoC 刷新之前独立启动 集成在 ApplicationContext 的 refresh() 中
    自动配置 @EnableAutoConfiguration + spring.factories
    条件化 Bean @ConditionalOnClass 等
    启动性能 极快(无复杂 SPI 加载) 较慢(大量自动配置扫描)
    配置加载 application.properties 简单加载 ConfigDataEnvironment 支持多 profile / 导入

    核心差异:Spring Boot 把“嵌入容器”变成 IoC 容器的一等公民——WebServer 作为一个 Bean 被管理,而自研 CodeStats 的 Catalina 是独立于 IoC 容器之外运行的。这使得 Spring Boot 可以在 refresh() 过程中利用容器内的 ServletContextInitializer 动态注册 Servlet/Filter,而自研版必须在 load() 阶段静态配置 DispatcherServlet。


    五、三方启动流程横向对比表

    对比维度自研 CodeStatsSpring Framework(传统)Spring Boot
    入口类 Bootstrap.main() AnnotationConfigApplicationContext SpringApplication.run()
    容器刷新 手工实现 refresh() 模板 同样模板,但扩展点极为丰富 复用 Spring 的 refresh(),但前置大量准备
    Web 服务器 自研嵌入式 Tomcat(Catalina) 需外部部署(如 Tomcat、Jetty) 内嵌 Tomcat/Jetty/Undertow,自动配置
    Bean 定义扫描 仅支持类路径下的 @Component 注解 支持注解、XML、JavaConfig、包扫描 相同,但结合自动配置导入额外配置类
    条件化注册 无原生支持(需 @Profile 有限) @Conditional 体系(类、Bean、资源等)
    启动耗时(空项目) ≈200ms ≈600ms ≈1200ms(自动配置加载)
    学习曲线 陡峭(需理解全栈实现) 平缓(文档丰富) 极平缓(约定大于配置)
    可扩展性 低(缺少生命周期钩子) 极高(BeanPostProcessor 无处不在) 极高(AutoConfigurationImportFilter)

    六、设计思想的升华:为什么我们要再造轮子?

    6.1 极简主义 VS 企业级完备

    自研 CodeStats 的核心追求是 教学演示与透明化。它没有复杂的 SPI 加载机制,没有数百个 BeanPostProcessor,所有代码都清晰可见。例如,DispatcherServlet 的路由匹配直接用正则解析,而 Spring MVC 则引入了 HandlerMapping、HandlerAdapter、HandlerExceptionResolver 等一系列抽象。这种简化让初学者能快速理解 “一个请求从 socket 到 controller 的全路径”。

    6.2 连接池的“微型”实现

    SimpleDataSource 使用 Semaphore 控制最大并发连接数,用 BlockingQueue 存放空闲连接,总代码不到 200 行。相比之下,HikariCP 几千行代码针对各种边界情况优化。但自研版本却清晰地展示了 “限流 + 复用” 的核心思想,这正是连接池的本质。

    6.3 Mapper 代理:动态代理的实战

    MapperProxy 通过 InvocationHandler 将接口方法调用转换为 SQL 执行,这是 Java 动态代理最经典的案例。Spring 的 MyBatis 整合也是如此,但自研版剥离了 XML 解析,仅依靠注解,让开发者直观感受 “接口方法如何变为 SQL 查询”。

    6.4 WWAIC 范式:AI 驱动的全栈开发

    CodeStats 的诞生方式本身就是一种范式创新——它完全由 AI(DeepSeek)生成,人类开发者仅提供架构提示和一周的上下文管理。WWAIC(全周项目 AI 工程)的核心思想是:让 AI 承担完整的系统实现,人类聚焦于架构设计与需求拆解。CodeStats 证明了这种方法论的可行性:一个拥有 IoC、MVC、Tomcat、连接池、Mapper 的完整框架,可以在 7 天内由 AI 从零构建。这与传统的“AI 辅助编程”(仅生成代码片段)有本质区别。


    七、总结:从自研到主流,理解框架的进化之路

    通过对比三个启动流程,我们可以清晰地看到:

    • 自研 CodeStats:一个完整的“最小可行框架”,麻雀虽小五脏俱全。它的价值在于教育与范式验证——让开发者亲手触摸 IoC、AOP、MVC、ORM 的核心实现,同时作为 WWAIC 范式的首个实证项目。

    • Spring Framework:将扩展性做到极致,通过 BeanPostProcessor 和 BeanFactoryPostProcessor 构建了庞大的生态基石。

    • Spring Boot:在 Spring Framework 之上封装了“自动配置”和“内嵌服务器”,简化了运维,提高了开发效率。

    对于技术人而言,精通 Spring 是职业必备,亲手写一个 Spring 则是内功修炼。CodeStats 项目正是这样一个内功修炼的绝佳案例。它让我们明白:所有看似黑魔法的框架,底层都是设计模式的朴素运用。

    你可以从 Gitee 获取 CodeStats 完整源码,亲自运行 Bootstrap.main(),体验一个纯自研 Java Web 框架启动时的激动心跳。更可以以此为起点,探索 WWAIC 范式下 AI 驱动的全栈开发新可能。

    点赞、收藏、评论,让更多人看到技术干货!


    🔗 资源汇总:

    • Gitee:https://gitee.com/zhouzuoli/code-stats.git

    • CSDN 项目总览:从零手写 Spring:一周之内用 AI 实现自研 IoC、MVC 和嵌入式 Tomcat-CSDN博客

    • WWAIC 概念定义:新型AI编程范式 全周 AI 编程(Whole-Week AI Coding,WWAIC)-CSDN博客

    • WWAIC 实战文章:新型AI编程范式WWAIC实战:从零手写HTTP服务器到全栈Java框架,一周搞定!-CSDN博客

    赞(0)
    未经允许不得转载:171主机测评 » 自研 CodeStats 框架:与 Spring Framework、Spring Boot 启动流程的深度解析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址