欢迎光临
我们一直在努力

从零自研 Java Web 框架:30 个核心问题系统拆解全流程

告别黑箱,开源项目真实可运行 30 个核心问题 + 3 万行自研代码,从 CPU 指令到手写 Tomcat、IoC、Mapper,彻底打通全链路


作者介绍

CodeStats,资深底层技术爱好者与实战派架构师,WWAIC(全周 AI 编程)范式创始人。专注计算机体系结构、操作系统内核、Java 虚拟机实现原理与自研框架落地。长期在 CSDN 分享硬核技术文章,手写 IoC 容器、嵌入式 Tomcat、MyBatis 风格 Mapper、连接池及代码分析引擎,致力于用通俗语言讲透 Java 程序从 CPU 指令到 Web 框架的完整运行逻辑。

💡 个人代表项目 CodeStats —— 一个完全自研、零商业依赖的 Java Web 平台,100% 代码由 AI 辅助生成,一周内从零交付可运行系统。本文所有示例均取自该项目真实源码。


📑 目录(30 个问题)

  • CPU 如何执行一条指令?

  • 中断如何实现“并发”假象?

  • 用户态与内核态如何切换?

  • 进程和线程的本质区别是什么?为什么线程切换更轻量?

  • 如何手写一个 IoC 容器?

  • 如何手写一个 MVC 框架?

  • 如何手写嵌入式 Tomcat?

  • 如何手写 MyBatis 风格的 Mapper?

  • 如何手写数据库连接池?

  • 如何手写 JdbcTemplate?

  • 如何手写日志框架?

  • 如何手写缓存框架?

  • 如何手写 Stream 惰性求值?

  • 如何手写类加载隔离?

  • 如何手写分页插件?

  • 如何手写 Session 管理?

  • 如何手写 Filter 链?

  • 如何手写静态资源服务器?

  • 如何手写文件上传解析器?

  • 如何手写 JSON 序列化器?

  • 代码分析引擎(Pipeline 模式)

  • 依赖分析(词法扫描 + 循环检测)

  • NIO 如何解决 C10K 问题?

  • 事务管理器如何实现?

  • AOP 动态代理的核心是什么?

  • Spring Boot 自动配置如何工作?

  • Feign 声明式 HTTP 客户端如何模拟?

  • 一级/二级缓存如何设计?

  • WWAIC 范式是什么?

  • 全链路自洽思维如何建立?


  • 1. CPU 如何执行一条指令?

    一句话核心原理

    冯·诺依曼架构:程序 = 内存中连续排列的指令。CPU 无限循环:取指 → 译码 → 执行 → 写回,PC(程序计数器)指向下一条指令。

    设计思路

    设计一个指令模拟器:byte[] memory 存指令,int pc 做计数器,switch(opcode) 执行。指令长度可变(1~3 字节),PC 累加当前指令长度。

    CodeStats 中的体现

    Connector 的事件循环是同样的无限循环模型:

    java

    // Connector.java
    while (running) {
    Socket socket = serverSocket.accept(); // 阻塞等待“事件”
    threadPool.submit(() -> process(socket)); // 处理“事件”
    }


    2. 中断如何实现“并发”假象?

    一句话核心原理

    硬件定时器每隔 1ms 发送中断信号。CPU 保存当前进程的 PC 和寄存器,切换到内核调度器,再恢复另一个进程的现场。每秒切换上千次,我们以为“同时运行”。

    设计思路

    设计协作式调度器:一个定时器线程每隔 10ms 主动调用 yield(),切换当前运行的 Runnable。

    CodeStats 中的体现

    线程池中的多个线程由 OS 内核调度,Java 线程 1:1 映射到 OS 线程:

    java

    threadPool.submit(() -> process(socket));
    // 操作系统自动中断当前线程,切换到另一个线程


    3. 用户态与内核态如何切换?

    一句话核心原理

    CPU 特权级:Ring 0(内核态) 可执行所有指令,Ring 3(用户态) 受限。用户程序想读文件,执行 syscall 指令,CPU 切换到 Ring 0,跳转到内核函数。

    设计思路

    设计一个系统调用门:定义 trap(int sysno, …),根据 sysno 调用对应的内核函数。

    CodeStats 中的体现

    JdbcTemplate 底层调用 DriverManager.getConnection(),最终触发 Socket 的 read 系统调用。


    4. 进程和线程的本质区别是什么?为什么线程切换更轻量?

    一句话核心原理

    • 进程:拥有独立页表,切换需换页表 → TLB 全部失效 → 开销大

    • 线程:共享进程页表,只需保存私有栈和寄存器 → TLB 保持有效 → 开销小

    设计思路

    设计“轻量级线程”模型:多个任务共享同一个内存视图,各自持有独立的栈。

    CodeStats 中的体现

    连接池中的多个线程共享 idleConnections(堆对象),但每个线程有自己的栈帧:

    java

    Connection conn = idleConnections.poll(); // 多个线程同时调用,线程安全


    5. 如何手写一个 IoC 容器?

    一句话核心原理

    三步:扫描包找出 @Component 等注解类 → 创建 BeanDefinition → 实例化 Bean,通过反射注入 @Autowired 字段。

    设计思路

    • BeanDefinition:beanClassName、scope、lazyInit

    • BeanFactory:singletonObjects 缓存 + getBean()

    • 注入:遍历字段,field.set(bean, dependency)

    CodeStats 实现代码

    java

    // DefaultListableBeanFactory.java
    protected void populateBean(Object bean, BeanDefinition bd) throws Exception {
    for (Field field : bean.getClass().getDeclaredFields()) {
    if (field.isAnnotationPresent(Autowired.class)) {
    field.setAccessible(true);
    Object dependency = resolveDependency(field, bean);
    field.set(bean, dependency);
    }
    }
    }

    // 多候选 Bean 处理:@Qualifier 或字段名匹配,或 @Primary
    protected Object resolveDependency(Field field, Object bean) throws Exception {
    Map<String, ?> candidates = getBeansOfType(field.getType());
    if (candidates.size() == 1) return candidates.values().iterator().next();
    Qualifier qualifier = field.getAnnotation(Qualifier.class);
    String targetBeanName = qualifier != null ? qualifier.value() : field.getName();
    if (candidates.containsKey(targetBeanName)) return candidates.get(targetBeanName);
    for (Object candidate : candidates.values()) {
    if (candidate.getClass().isAnnotationPresent(Primary.class)) return candidate;
    }
    throw new Exception("Multiple beans found, use @Qualifier or @Primary");
    }


    6. 如何手写一个 MVC 框架?

    一句话核心原理

    DispatcherServlet 作为前端控制器:初始化扫描 @Controller 收集映射;请求到达时匹配路径,解析参数,反射调用方法;若方法有 @ResponseBody,将返回值 JSON 序列化后写入响应。

    设计思路

    • HandlerMapping:path → (controller, method, isResponseBody)

    • ParamBinder:支持 @RequestParam、@PathVariable、@RequestBody 及类型转换

    • 静态资源处理:路径安全校验后从 webapps/ 读取文件

    CodeStats 实现代码

    java

    // DispatcherServlet.java
    private void processRequest(HttpServletRequest req, HttpServletResponse res) {
    for (HandlerMapping hm : handlerMappings) {
    if (req.getUri().matches(hm.regex)) {
    Map<String, String> pathVars = extractPathVars(matcher, hm.varNames);
    Object[] args = ParamBinder.resolveParameters(hm.method, req, res, pathVars);
    Object result = hm.method.invoke(hm.controller, args);
    if (hm.isResponseBody) {
    res.setContentType("application/json; charset=utf-8");
    res.write(toJson(result));
    }
    res.send();
    return;
    }
    }
    serveStaticFile(uri, res);
    }


    7. 如何手写嵌入式 Tomcat?

    一句话核心原理

    Tomcat 核心架构:Server → Service → Connector + Engine → Host → Context → Wrapper。

    • Connector 监听端口,解析 HTTP

    • Pipeline-Valve 责任链处理请求

    • Wrapper 包装并调用 Servlet

    设计思路

    • Connector:ServerSocket + 线程池,解析请求行/Header/Body

    • Pipeline:List<Valve> + 递归调用 invokeNext()

    • Context:维护 servletMappings(URL → servletName)

    CodeStats 实现代码

    java

    // Connector.java
    public void start() {
    serverSocket = new ServerSocket(port);
    while (running) {
    Socket socket = serverSocket.accept();
    threadPool.submit(() -> {
    Request req = new Request(socket.getInputStream());
    req.parse();
    Response res = new Response(socket.getOutputStream());
    engine.getPipeline().invoke(req, res);
    });
    }
    }

    // SimplePipeline.java
    public void invoke(Request request, Response response) throws Exception {
    new ValveChainImpl().invokeNext(request, response);
    }
    private class ValveChainImpl implements Valve.ValveChain {
    private int index = 0;
    public void invokeNext(Request req, Response resp) throws Exception {
    if (index < valves.size())
    valves.get(index++).invoke(req, resp, this);
    else if (basic != null)
    basic.invoke(req, resp, this);
    else
    container.getPipeline().invoke(req, resp);
    }
    }


    8. 如何手写 MyBatis 风格的 Mapper?

    一句话核心原理

    @Mapper 标记接口,启动时扫描并为每个接口创建 JDK 动态代理。MapperProxy.invoke() 中:获取 @Select 注解的 SQL → 解析 #{xxx} 为 ? → 构建参数 → 调用 JdbcTemplate 执行 → 结果映射。

    设计思路

    • SqlParser:正则替换 #{xxx} 为 ?,提取参数名列表

    • 参数构建:从 @Param 或方法参数对象中获取值

    • 结果映射:根据返回类型(List<T> / T / int)选择不同执行方法

    CodeStats 实现代码

    java

    // MapperProxy.java
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Select select = method.getAnnotation(Select.class);
    String sql = select.value();
    ParsedSql parsed = SqlParser.parse(sql); // "SELECT * FROM user WHERE id = ?", ["id"]
    Object[] paramValues = buildParamValues(method, args, parsed.getParamNames());

    Class<?> returnType = method.getReturnType();
    if (returnType == List.class) {
    Class<?> elementType = extractElementType(method);
    return jdbcTemplate.queryForList(parsed.getSql(), elementType, paramValues);
    } else {
    return jdbcTemplate.queryForObject(parsed.getSql(), returnType, paramValues);
    }
    }


    9. 如何手写数据库连接池?

    一句话核心原理

    核心三组件:空闲队列(BlockingQueue)、限流器(Semaphore)、连接验证(validationQuery)。通过代理覆盖 close() 实现归还而非真正关闭。

    设计思路

  • 初始化创建 minIdle 个连接放入队列

  • getConnection():获取 Semaphore 许可 → 从队列 poll()(空则新建) → 验证无效则递归重试 → 返回 PooledConnection 包装

  • 归还:若队列未满则放回,否则关闭;释放 Semaphore

  • CodeStats 实现代码

    java

    // SimpleDataSource.java
    public Connection getConnection() throws SQLException {
    semaphore.acquire();
    Connection conn = idleConnections.poll();
    if (conn == null) {
    conn = DriverManager.getConnection(url, username, password);
    }
    if (!isValid(conn)) {
    conn.close();
    return getConnection();
    }
    return new PooledConnection(conn, this);
    }

    void returnConnection(Connection conn) {
    if (idleConnections.size() < maxIdle) {
    idleConnections.offer(conn);
    } else {
    conn.close();
    }
    semaphore.release();
    }


    10. 如何手写 JdbcTemplate?

    一句话核心原理

    模板方法模式:固定 SQL 执行骨架,变化的部分(结果映射)通过回调接口 RowMapper 开放。

    设计思路

    • query(sql, rowMapper, args):获取连接 → 创建 PreparedStatement → 绑定参数 → 执行 → 遍历 ResultSet 调用 rowMapper.mapRow()

    • queryForObject:单结果,空则 null,超过一条抛异常

    • 自动映射:下划线转驼峰 + TypeConverter 类型转换

    CodeStats 实现代码

    java

    // JdbcTemplate.java
    public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object… args) {
    try (Connection conn = getConnection();
    PreparedStatement ps = conn.prepareStatement(sql)) {
    for (int i = 0; i < args.length; i++) ps.setObject(i + 1, args[i]);
    ResultSet rs = ps.executeQuery();
    List<T> results = new ArrayList<>();
    while (rs.next()) {
    results.add(rowMapper.mapRow(rs));
    }
    return results;
    }
    }

    public static <T> RowMapper<T> beanRowMapper(Class<T> clazz) {
    return rs -> {
    T bean = clazz.getDeclaredConstructor().newInstance();
    ResultSetMetaData meta = rs.getMetaData();
    for (int i = 1; i <= meta.getColumnCount(); i++) {
    String columnName = meta.getColumnLabel(i);
    String propertyName = underscoreToCamel(columnName); // user_name → userName
    Object value = rs.getObject(i);
    setProperty(bean, propertyName, value); // 反射 + TypeConverter
    }
    return bean;
    };
    }


    11. 如何手写日志框架?

    核心原理

    Appender + Layout + Filter,模板方法 + 策略模式。

    • Appender:输出目的地(控制台、文件、滚动文件、异步)

    • Layout:格式化 LogEvent(PatternLayout 支持 %d、%level、%msg、%ex)

    • Filter:责任链过滤(如 LevelRangeFilter)

    设计思路

    LoggerFactory 从 XML 加载配置,Logger 门面提供 log.info() 等方法,Appender.doAppend() 通过模板方法调用子类实现的 append()。

    CodeStats 关键类

    LoggerFactory, ConsoleAppender, FileAppender, RollingFileAppender, AsyncAppender, PatternLayout, LevelRangeFilter


    12. 如何手写缓存框架?

    核心原理

    ConcurrentHashMap + TTL + 定期清理。

    • 每个缓存条目记录 expireTime

    • get() 时惰性删除过期条目

    • 后台线程定期清理全量过期条目

    设计思路

    统一 Cache<K,V> 接口,支持 put(key, value, ttl)、get(key)、computeIfAbsent。实现分为 LocalCache(基于 ConcurrentHashMap)和 CaffeineCache(可选)。

    CodeStats 关键类

    Cache, LocalCache, CacheFactory, CacheManager


    13. 如何手写 Stream 惰性求值?

    核心原理

    流水线模式:中间操作不执行,只记录 PipelineStage;终端操作触发遍历,每个元素依次经过所有 stage。

    设计思路

    • MyStream 接口:filter, map, forEach

    • PipelineStage:process(input, sink) 函数式接口

    • 构建阶段:每次中间操作返回新 MyStreamImpl,合并 stage 链

    • 执行阶段:forEach 时从最外层 stage 开始,对源集合每个元素递归调用

    CodeStats 关键类

    MyStreamImpl, MyPipelineStage


    14. 如何手写类加载隔离?

    核心原理

    打破双亲委派模型:优先从当前 Web 应用加载类,再委托父加载器。 Tomcat 的 WebappClassLoader 先 findClass() 再 super.loadClass()。

    设计思路

    继承 URLClassLoader,重写 loadClass():

  • 已加载类直接返回

  • 系统类(java.、javax.)委托父加载器

  • 优先 findClass() 从当前应用 WEB-INF/classes 和 WEB-INF/lib 加载

  • 未找到再委托父加载器

  • CodeStats 实现代码

    WebappClassLoader.java(见项目源码)


    15. 如何手写分页插件?

    核心原理

    MyBatis 插件机制通过 ThreadLocal 传递分页参数,在 Executor 拦截器中改写 SQL,追加 LIMIT / ROWNUM。

    设计思路

    PageHelper.startPage(page, size) → 存入 ThreadLocal → 拦截 Executor.query() → 解析原 SQL,生成 COUNT 和分页 SQL → 执行并清理 ThreadLocal。

    CodeStats 实现代码

    DynamicSqlExecutor.executePageQuery() 直接支持分页,未用插件,但原理相同。


    16. 如何手写 Session 管理?

    核心原理

    Cookie 中存放 JSESSIONID,服务器端 Map<String, HttpSession> 存储会话数据。 Request.getSession() 根据 Cookie 中的 JSESSIONID 查找或创建新 Session。

    设计思路

    • SessionManager:静态 ConcurrentHashMap + 原子 ID 生成器

    • HttpSessionImpl:存储属性、创建时间、最后访问时间

    • Request 解析 Cookie,Response 添加 Set-Cookie 头

    CodeStats 关键类

    SessionManager, HttpSessionImpl


    17. 如何手写 Filter 链?

    核心原理

    责任链模式:ApplicationFilterChain 维护 Filter 列表和当前索引,递归调用 doFilter()。

    设计思路

    FilterChain.doFilter(request, response) 中:若还有下一个 Filter 则调用它,否则调用 servlet.service()。每个 Filter 可在调用前后执行自定义逻辑。

    CodeStats 实现代码

    ApplicationFilterChain.java


    18. 如何手写静态资源服务器?

    核心原理

    路径安全校验(防止 ../ 越权),MIME 类型映射,直接通过 Files.copy() 输出文件流。

    设计思路

    serveStaticFile(uri, res):

  • 将 URI 转换为文件系统路径(以 webapps/ 为根)

  • 调用 Path.normalize(),检查是否仍在根目录下

  • 根据扩展名设置 Content-Type

  • Files.copy(file, outputStream)

  • CodeStats 实现代码

    DispatcherServlet.serveStaticFile()


    19. 如何手写文件上传解析器?

    核心原理

    解析 multipart/form-data 请求体,查找边界字符串,读取每个 part 的头部和内容,将文件内容写入临时文件,普通字段存入 Map。

    设计思路

    • MultipartResolver:

      • 从 Content-Type 提取 boundary

      • 使用 BoundaryFinder 高效匹配边界

      • 逐个 part 解析:读取头部 → 判断是普通字段还是文件 → 写入临时文件或直接存值

    • 实现 AutoCloseable,请求结束后删除临时文件

    CodeStats 关键类

    MultipartResolver, BoundaryFinder, FileItem


    20. 如何手写 JSON 序列化器?

    核心原理

    反射遍历对象字段,递归序列化,用 IdentityHashMap 检测循环引用,忽略 static 和 transient 字段。

    设计思路

    JsonUtil.toJson(obj):

    • null → "null"

    • String → 转义引号、换行等

    • Number / Boolean → 直接 toString()

    • Map → 序列化为 {…}

    • Collection / 数组 → 序列化为 […]

    • 其他 JavaBean → 反射获取所有字段(包括私有),序列化为 {"fieldName": value}

    CodeStats 实现代码

    JsonUtil.java


    21. 代码分析引擎(Pipeline 模式)

    核心原理

    Pipeline 模式将分析流程拆分为多个独立 Stage: CollectStage → ParallelAnalyzeStage → AggregateStage → OutputStage

    设计思路

    • CollectStage:递归扫描目录,过滤扩展名和排除路径

    • ParallelAnalyzeStage:多线程并行分析每个文件,统计代码行/注释行/空行/复杂度

    • AggregateStage:按指定字段排序,汇总语言分布

    • OutputStage:输出 JSON/CSV/Console 格式

    CodeStats 关键类

    Pipeline, CollectStage, ParallelAnalyzeStage, AggregateStage, OutputStage


    22. 依赖分析(词法扫描 + 循环检测)

    核心原理

    通过词法扫描 Java 源码提取包名、导入、类声明、字段类型、方法返回类型/参数类型,通过同包、导入、java.lang 隐式导入规则解析全限定名。用 Tarjan 算法检测循环依赖。

    设计思路

    • SimpleJavaLexer:扫描 Token,跳过注释和字符串

    • JavaDependencyExtractor:解析包名、导入、类声明,收集类型引用

    • TypeNameResolver:将简单名解析为全限定名

    • DependencyGraph:使用 Tarjan 算法找出强连通分量(循环依赖组)

    CodeStats 关键类

    JavaDependencyExtractor, SimpleJavaLexer, TypeNameResolver, DependencyGraph


    23. NIO 如何解决 C10K 问题?

    核心原理

    使用 Selector 单线程管理成千上万个非阻塞 Channel,只在有事件(可读/可写/连接)时才处理,避免了 BIO 中每个线程阻塞在 read() 上。

    设计思路

    • ServerSocketChannel 设置为非阻塞,注册 OP_ACCEPT

    • Selector.select() 阻塞等待事件

    • 新连接注册 OP_READ,数据到来时提交给线程池处理

    • 线程池只负责业务逻辑,不阻塞 I/O

    CodeStats 实现代码

    Connector 的 NIO 版本(项目中有两种实现,NIO 版本见源码)


    24. 事务管理器如何实现?

    核心原理

    AOP 代理 + Connection.setAutoCommit(false)。将事务注解的方法通过动态代理包裹,在方法执行前开启事务,执行后提交,异常时回滚。

    设计思路

    自定义 @Transactional 注解,通过 BeanPostProcessor 为带有该注解的 Bean 生成代理,代理中管理 Connection 的事务状态。

    CodeStats 实现代码

    预留接口,完整实现可参考 TransactionProxy 示例类。


    25. AOP 动态代理的核心是什么?

    核心原理

    JDK 动态代理(基于接口)或 CGLIB(基于子类)在运行时生成代理对象,在代理中插入横切逻辑(如日志、事务)。

    设计思路

    InvocationHandler.invoke() 中:在 method.invoke() 前后执行增强代码。结合 BeanPostProcessor 可在 Bean 初始化后替换为代理对象。

    CodeStats 关键类

    MapperProxy(类比 AOP 的环绕通知),BeanPostProcessor(预留扩展)


    26. Spring Boot 自动配置如何工作?

    核心原理

    @EnableAutoConfiguration 通过 SpringFactoriesLoader 加载 META-INF/spring.factories 中配置的 AutoConfiguration 类,这些类使用 @Conditional 条件注解按需生效。

    设计思路

    CodeStats 未完整实现自动配置,但通过 ConfigLoader 读取 application.properties 提供了类似的效果。可扩展为扫描 META-INF/services 加载配置类。

    CodeStats 关键类

    ConfigLoader


    27. Feign 声明式 HTTP 客户端如何模拟?

    核心原理

    与 MyBatis Mapper 完全一致:通过 @FeignClient 标记接口,FeignClientFactoryBean 创建 JDK 动态代理,代理中将方法调用转换为 HTTP 请求(拼接 URL、填充参数、执行请求并解码响应)。

    设计思路

    参考 MapperProxy 的实现,将 SQL 执行替换为 HttpURLConnection 或 HttpClient 调用。

    CodeStats 关键类

    MapperProxy(可直接修改为 HTTP 代理)


    28. 一级/二级缓存如何设计?

    核心原理

    • 一级缓存:SqlSession 级别的 PerpetualCache(HashMap),会话关闭或执行增删改时清空

    • 二级缓存:Mapper 级别的缓存,跨会话共享,实体类需实现 Serializable

    设计思路

    Executor 在查询前先检查一级缓存,再检查二级缓存;update 操作清空相关缓存。

    CodeStats 关键类

    PerpetualCache(预留接口)


    29. WWAIC 范式是什么?

    核心原理

    Whole-Week AI Coding:开发者在一周内将完整项目的需求、架构设计、模块划分、技术栈约束一次性提交给 AI,由 AI 生成可运行的完整系统。CodeStats 是该范式的首个实证项目。

    设计思路

    人负责顶层设计(分层、接口、核心类),AI 负责生成实现代码。开发者的角色从代码编写者转变为架构设计者 + 集成验证者。

    CodeStats 关键类

    整个 CodeStats 项目就是 WWAIC 的产物。


    30. 全链路自洽思维如何建立?

    核心原理

    从硬件(CPU 指令)到操作系统(进程线程、内存管理),再到 JVM(类加载、栈帧、GC),最后到框架(IoC、MVC、ORM、Tomcat),所有技术都遵循“简单规则层层组合”的原则。

    设计思路

    以 30 个核心问题为主线,手写每个关键模块的迷你实现,从而建立从底层到上层的完整知识图谱。

    最终检验

    ✅ 能在一张白纸上画出从 Java 代码到 CPU 指令的全链路执行流程,并能用自研框架跑通一个完整的 Web 应用。


    开源项目:CodeStats

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

    一个完全自研的 Java Web 框架,包含:

    • ✅ 自研 IoC 容器

    • ✅ 自研 MVC 框架

    • ✅ 自研嵌入式 Tomcat

    • ✅ 自研 MyBatis 风格 Mapper

    • ✅ 自研数据库连接池

    • ✅ 自研 JdbcTemplate

    • ✅ 自研日志框架

    • ✅ 自研缓存框架

    • ✅ 代码分析引擎(Pipeline 模式)

    • ✅ 前端管理界面(数据库客户端、文件管理、AI 助手)

    📦 全部代码 3 万行,100% 可运行,无黑盒。欢迎 Star、Clone、学习、扩展!


    写在最后

    计算机科学没有魔法。 所有看似神奇的框架,底层都是简单规则的层层组合。

    当你亲手实现了 IoC 容器、Tomcat 连接器、Mapper 代理之后,再去看 Spring、MyBatis 源码,你会发现:原来就这么回事。

    希望这 30 个问题能帮你打通从 CPU 到 Controller 的任督二脉,建立全链路自洽的底层认知。

    开始动手吧!

    赞(0)
    未经允许不得转载:171主机测评 » 从零自研 Java Web 框架:30 个核心问题系统拆解全流程
    分享到: 更多 (0)

    评论 抢沙发

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