0%

架构演进:从集中到分布式的迭代之路

架构的演进始终围绕着业务增长带来的复杂度挑战,从最初的简单集中式到复杂的分布式,每一步都是为了更好地适配业务规模、团队协作和技术能力的提升。

一、单一应用架构:简单起步的集中式方案

核心特征

所有功能模块(如用户管理、订单处理、商品展示等)集中在一个应用中,打包成单一部署单元(如 WAR 包),运行在一台服务器上,共享同一个数据库。

适用场景

  • 业务初期:用户量少(如日均几千访问)、功能简单(如小型企业官网、内部管理系统)。
  • 团队规模小:1-3 人开发,无需复杂协作流程。

优势

  • 开发部署高效:无需考虑跨服务通信,代码修改后直接打包部署,初期迭代速度快。
  • 资源成本低:单服务器 + 单数据库即可支撑,硬件和运维成本极低。

局限

  • 扩展性瓶颈:随着功能增加(如从 3 个模块增至 10 个模块),代码量激增(可能超 10 万行),模块间耦合严重(如一个模块的 bug 可能影响整个系统)。
  • 性能风险:所有请求集中在一台服务器,用户量增长后(如日均访问超 10 万),容易出现 CPU 占用过高、数据库连接耗尽等单点故障。
  • 协作困难:多人开发同一应用时,代码冲突频繁,需频繁合并分支,影响迭代效率。

二、垂直应用架构:按业务拆分的分散式尝试

核心特征

阅读全文 »

Spring MVC 参数解析机制详解:从接口到实战全流程

Spring MVC 的参数解析是连接 “HTTP 请求数据” 与 “Controller 方法参数” 的核心桥梁,负责将请求中的 URL 参数、请求头、请求体等数据,自动转换为 Controller 方法所需的 Java 类型参数(如 StringUser 对象、MultipartFile 等)。其核心是 HandlerMethodArgumentResolver 接口,通过多种实现类覆盖不同场景的参数解析需求,并结合 HttpMessageConverter(请求体转换)、Converter(类型转换)、Validator(数据验证)等组件,实现灵活且低侵入的参数绑定。从 “核心接口→解析器分类→解析流程→消息转换→参数转换→数据验证” 六个维度,彻底讲透 Spring MVC 参数解析的底层逻辑与实战应用。

核心接口:HandlerMethodArgumentResolver

HandlerMethodArgumentResolver 是所有参数解析器的顶层接口,定义了参数解析的通用规范,仅包含两个核心方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface HandlerMethodArgumentResolver {
/**
* 1. 判断当前解析器是否支持解析指定类型的参数
* @param parameter Controller 方法的参数描述(包含参数类型、注解等信息)
* @return true:支持解析;false:不支持,交给下一个解析器
*/
boolean supportsParameter(MethodParameter parameter);

/**
* 2. 执行参数解析,将请求数据转换为 Controller 方法所需的参数值
* @param parameter 参数描述
* @param mavContainer 模型容器(存储模型数据,如 Model)
* @param webRequest 封装 HTTP 请求(可获取请求参数、请求头、请求体等)
* @param binderFactory 数据绑定工厂(用于参数绑定与验证)
* @return 解析后的参数值(如 String、User 对象)
* @throws Exception 解析过程中抛出的异常(如参数格式错误)
*/
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}

核心设计思想:职责链模式

Spring MVC 维护一个 HandlerMethodArgumentResolver 列表(由 HandlerMethodArgumentResolverComposite 组合管理),当解析参数时:

  1. 遍历所有解析器,通过 supportsParameter 判断是否支持当前参数;
  2. 找到第一个支持的解析器,调用 resolveArgument 完成解析;
  3. 若所有解析器均不支持,抛出 IllegalStateException(如 “Could not resolve parameter [xxx]”)。

参数解析器分类与核心实现类

Spring MVC 提供了数十个 HandlerMethodArgumentResolver 实现类,覆盖从 “简单参数” 到 “复杂对象” 的所有场景。按功能可分为 6 大类,以下是关键实现类的解析:

分类 核心实现类 适用场景 关键特性
路径参数解析 PathVariableMethodArgumentResolver 处理 @PathVariable 注解的参数(非 Map 类型) 从 URL 路径中提取参数(如 /user/{id}id 值)
PathVariableMapMethodArgumentResolver 处理 @PathVariable 注解的 Map 类型参数 将所有路径参数封装为 Map(如 @PathVariable Map<String, String> params
请求参数解析 RequestParamMethodArgumentResolver 处理 @RequestParam 注解、基本类型(String/Integer)、MultipartFile 从 URL 查询参数或表单中提取参数;支持参数必填校验
RequestParamMapMethodArgumentResolver 处理 @RequestParam 注解的 Map 类型参数 将同名参数封装为 Map(如 @RequestParam Map<String, String> params
请求体解析 RequestResponseBodyMethodProcessor 处理 @RequestBody 注解的参数 依赖 HttpMessageConverter 将请求体(如 JSON)转换为 Java 对象
HttpEntityMethodProcessor 处理 HttpEntity/RequestEntity 类型参数 封装整个请求(包含请求头 + 请求体)为 HttpEntity 对象
请求头 / Cookie 解析 RequestHeaderMethodArgumentResolver 处理 @RequestHeader 注解的参数(非 Map 类型) 从请求头中提取参数(如 @RequestHeader("User-Agent") String userAgent
ServletCookieValueMethodArgumentResolver 处理 @CookieValue 注解的参数 从 Cookie 中提取参数(如 @CookieValue("JSESSIONID") String sessionId
Servlet 原生对象解析 ServletRequestMethodArgumentResolver 处理 HttpServletRequest/HttpServletResponse/HttpSession 等类型参数 直接注入 Servlet 原生对象,无需额外转换
模型 / 会话参数解析 ModelAttributeMethodProcessor 处理 @ModelAttribute 注解的参数 将请求参数绑定为 Java Bean(如表单提交的 User 对象)
SessionAttributeMethodArgumentResolver 处理 @SessionAttribute 注解的参数 从 Session 中提取已存储的属性(如 @SessionAttribute("loginUser") User user

关键实现类详解

1. RequestParamMethodArgumentResolver(最常用)

负责解析 URL 查询参数、表单参数、基本类型参数,是日常开发中最频繁使用的解析器:

阅读全文 »

Tomcat 项目部署全攻略:三种方式详解与实战

Tomcat 作为 Java Web 应用的主流容器,提供了多种灵活的部署方式,适应不同的开发、测试和生产环境。本文详细讲解 Tomcat 部署 Web 项目的三种核心方式,分析其优缺点及适用场景,帮助开发者高效管理应用部署。

方式一:直接部署到webapps目录(最简单)

这是 Tomcat 最默认、最便捷的部署方式,无需额外配置,适合快速测试或小型应用。

部署步骤

  1. 准备应用包
    • 可以是解压后的 Web 应用文件夹(目录结构需包含WEB-INFMETA-INF等标准目录);
    • 也可以是WAR 包(Web Application Archive,将应用文件压缩为.war格式)。
  2. 放置到webapps目录
    将应用文件夹或 WAR 包复制到 Tomcat 安装目录的webapps文件夹下(如/usr/local/tomcat/webapps)。
  3. 自动部署
    • 若为 WAR 包,Tomcat 会自动解压(依赖server.xmlunpackWARs="true"配置),生成同名文件夹;
    • 启动 Tomcat 后,应用即可访问。

访问路径规则

  • 若应用文件夹(或解压后的 WAR 包文件夹)名为myapp,访问路径为:http://localhost:8080/myapp
  • 若文件夹名为ROOT(大写),则为默认应用,访问路径为:http://localhost:8080(无需加应用名)。

优缺点

  • 优点:零配置,操作简单,适合新手和快速部署;
  • 缺点:应用必须放在webapps目录,灵活性低;大规模部署时难以管理。

方式二:在server.xml中配置<Context>节点(灵活但不推荐)

通过修改 Tomcat 核心配置文件server.xml,手动指定应用路径,适合需要自定义部署路径的场景。

部署步骤

  1. 编辑server.xml
    打开conf/server.xml,在<Host>标签内添加<Context>节点:

阅读全文 »

HystrixCommand 执行原理:从 AOP 拦截到命令执行的全解析

Hystrix 通过@HystrixCommand注解实现对方法的容错增强,其底层依赖 AOP 切面拦截目标方法,封装执行逻辑(如熔断、隔离、降级)。本文结合源码详细解析 HystrixCommand 的执行流程,从注解拦截到命令执行的每一步核心逻辑。

AOP 入口:HystrixCommandAspect

Hystrix 通过HystrixCommandAspect切面类拦截所有标注@HystrixCommand的方法,这是执行流程的起点。

1. 切面定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Aspect
public class HystrixCommandAspect {
// 切点:拦截所有标注@HystrixCommand的方法
@Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")
public void hystrixCommandAnnotationPointcut() {}

// 环绕通知:处理拦截到的方法
@Around("hystrixCommandAnnotationPointcut()")
public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
// 1. 解析方法元数据(注解配置、参数等)
Method method = getMethodFromTarget(joinPoint);
MetaHolder metaHolder = createMetaHolder(joinPoint, method);

// 2. 创建Hystrix命令对象(封装执行逻辑)
HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);

// 3. 执行命令(根据执行类型同步/异步处理)
Object result = executeCommand(invokable, metaHolder);

return result;
}
}
阅读全文 »

@EnableZuulProxy 与 @EnableZuulServer 的区别:Zuul 网关的两种启用方式

在 Zuul 中,@EnableZuulProxy@EnableZuulServer是启用网关功能的两个核心注解,两者的差异主要体现在功能范围内置过滤器上。@EnableZuulProxy@EnableZuulServer的超集,提供了更完整的路由能力(如集成服务发现和负载均衡),而@EnableZuulServer仅包含基础网关功能。

核心差异:功能范围

注解 定位 核心能力 适用场景
@EnableZuulProxy 增强版网关(代理模式) 包含@EnableZuulServer的所有功能,额外支持: - 与服务发现(Eureka 等)集成 - 基于 Ribbon 的负载均衡 - 路由到注册中心的微服务 微服务架构(需动态路由到服务)
@EnableZuulServer 基础版网关(服务器模式) 仅支持静态路由(配置固定 URL)和基础过滤器,不依赖服务发现和 Ribbon 简单路由场景(无服务发现需求)

底层实现:自动配置类的继承关系

Zuul 的自动配置类清晰体现了两者的关系:
ZuulProxyAutoConfiguration 继承 ZuulServerAutoConfiguration,即@EnableZuulProxy包含@EnableZuulServer的所有配置,并额外添加了服务发现和负载均衡相关的 Bean。

阅读全文 »