❝Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!
项目初期,登录校验通常只需用户名和密码验证,通常采用硬编码方式完成基础验证:
public boolean validateLogin(String username, String password) {
if (username == null || username.length() < 5) {
System.out.println("用户名长度不足");
return false;
}
if (!password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[A-Za-z\\d]{8,}$")) {
System.out.println("密码强度不足");
return false;
}
return "admin".equals(username) && "Secret123".equals(password);
}
但随着用户量增加,安全需求不断升级:
验证码校验:防止脚本攻击
IP黑名单拦截:拦截高频攻击IP
设备指纹校验:增强场景化风控
每次新增需求都需在原有方法中插入if
判断,代码逐渐臃肿,演变成难以维护的“瑞士军刀式”代码。
牵一发而动全身:新增校验逻辑需修改核心方法,易引发连锁BUG。
流程僵化:校验顺序硬编码,无法动态调整。
可读性差:新人接手时难以理解逻辑编排的合理性。
传统实现方式演变为:
public boolean validateEverything(...) {
// 十几个校验逻辑挤在一起
}
已明显违反:
开闭原则:扩展需修改已有代码,而非通过新增类实现。
单一职责原则:一个方法承担过多校验职责。
迪米特法则:模块间耦合度过高。
将校验逻辑拆分为独立处理器,形成“质检流水线”,每个节点专注单一职责,失败则中断流程,成功则传递至下一节点。
public abstract class Handler {
private Handler next;
public Handler linkWith(Handler next) {
this.next = next;
return next;
}
public abstract boolean check(LoginRequest request);
protected boolean proceed(LoginRequest request) {
return next == null || next.check(request);
}
}
public class IPHandler extends Handler {
@Override
public boolean check(LoginRequest request) {
if (isBlacklisted(request.getIp())) {
log.warn("拦截可疑IP: {}", request.getIp());
return false;
}
return proceed(request);
}
private boolean isBlacklisted(String ip) {
// 查询IP黑名单库
}
}
将零散参数封装为对象,统一传递上下文:
public class LoginRequest {
private String username;
private String password;
private String captcha;
private String ip;
// 其他参数...
}
按需组合处理器,灵活控制校验顺序:
Handler chain = new UsernameHandler()
.linkWith(new CaptchaHandler())
.linkWith(new IPHandler())
.linkWith(new PasswordHandler());
@Test
void testRiskLogin() {
LoginRequest request = new LoginRequest(
"admin", "WrongPass123", "captcha", "192.168.10.100"
);
boolean result = chain.check(request);
assertFalse(result);
}
[校验] 用户名格式合法
[校验] 验证码校验通过
[风控拦截] 高风险IP
登录结果:失败
Spring Security的过滤器链是责任链模式的经典实现
public class FilterChainProxy implements Filter {
private List chains;
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
for (SecurityFilterChain f : chains) {
f.doFilter(req, res, chain); // 责任链传递
}
}
}
public class UsernamePasswordAuthenticationFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
// 认证逻辑处理
chain.doFilter(req, res); // 传递到下一过滤器
}
}
模式映射:
Handler
→ Filter
接口
linkWith()
→ Spring通过List
维护过滤器顺序
check()
→ doFilter()
方法
需要动态组合处理流程时
存在多个候选处理逻辑时
需解耦请求方与处理方时
定义抽象接口:约定处理与链式传递机制。
实现处理节点:每个类专注单一校验逻辑。
组装执行链:按需组合处理器。
封装上下文:统一传递参数。
避免长链:节点超过10个时建议拆分。
性能敏感场景慎用:链式调用存在轻微性能损耗。
统一异常处理:明确中断、继续等策略。
防循环引用:链配置需严格检测。
结合策略模式:动态替换处理器实现。
添加监控节点:记录各节点执行耗时。
优先级控制:通过@Order
注解调整顺序。