Spring HandlerInterceptor、BeanPostProcessor、MyBatis TypeHandler 行业级源码深度剖析与实战
一、引言
多接口+抽象类+责任链/策略模式是现代Java主流框架的基石。本文以Spring HandlerInterceptor、BeanPostProcessor、MyBatis TypeHandler为例,逐环节、逐行剖析其主流程、源码设计、内核机制、最佳实践与高阶应用。
二、主流程流程图与环节分布
三、Spring HandlerInterceptor 源码剖析
3.1 责任链环节拆解
1. preHandle
方法签名
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
内部逻辑
- 处理请求前的预处理逻辑(如鉴权、日志、限流)
- 返回
false
则中断后续流程
源码片段与详细注释
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 默认返回true,表示继续执行后续链路
return true;
}
// 省略其他方法...
}
案例:登录拦截
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = request.getHeader("Authorization");
if (token == null || !isValid(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
return true;
}
速记口诀
“前置拦截做校验,false短路链路断。”
2. postHandle
方法签名
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception;
内部逻辑
- 控制器执行后,渲染视图前的处理(如数据加工、日志)
源码片段
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
// 默认空实现
}
案例:统一给视图添加全局属性
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) {
if (modelAndView != null) {
modelAndView.addObject("globalVar", "value");
}
}
速记口诀
“控制之后视图前,加工数据全局用。”
3. afterCompletion
方法签名
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
内部逻辑
- 请求处理完成后(包括异常),用于资源清理、异常统计
源码片段
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
// 默认空实现
}
案例:统计接口耗时
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
long start = (Long)request.getAttribute("startTime");
long duration = System.currentTimeMillis() - start;
log.info("耗时: {}ms", duration);
}
速记口诀
“请求结束再清理,异常监控不可弃。”
3.4 行级源码剖析
以Spring的DispatcherServlet
部分源码为例:
// org.springframework.web.servlet.DispatcherServlet#doDispatch
for (HandlerInterceptor interceptor : mappedHandler.getInterceptors()) {
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
// 拦截器返回false,终止流程
triggerAfterCompletion(...);
return;
}
}
// handler.invoke()
for (HandlerInterceptor interceptor : interceptors) {
interceptor.postHandle(...);
}
triggerAfterCompletion(...);
注释:Spring内部遍历所有拦截器,依次调用
preHandle
,只要有一个返回false即短路。
3.5 参考资料
四、Spring BeanPostProcessor 源码剖析
4.1 生命周期钩子环节拆解
1. postProcessBeforeInitialization
方法签名
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
内部逻辑
- Bean初始化方法调用前执行(@PostConstruct之前)
源码片段
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean; // 默认返回原Bean
}
案例:自动代理
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if(bean instanceof SomeService) {
// 包装为代理对象
return Proxy.newProxyInstance(...);
}
return bean;
}
速记口诀
“初始化前可增强,返回原Bean最安全。”
2. postProcessAfterInitialization
方法签名
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
内部逻辑
- Bean初始化之后执行(AOP代理点)
源码片段
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
案例:AOP切面织入
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (需要AOP增强) {
return aopProxy.createProxy(bean);
}
return bean;
}
速记口诀
“初始化后织切面,增强Bean最方便。”
4.3 行级源码剖析
以Spring Bean工厂源码片段为例:
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
Object wrappedBean = bean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
wrappedBean = processor.postProcessBeforeInitialization(wrappedBean, beanName);
}
invokeInitMethods(beanName, wrappedBean, mbd);
for (BeanPostProcessor processor : getBeanPostProcessors()) {
wrappedBean = processor.postProcessAfterInitialization(wrappedBean, beanName);
}
注释:Spring会链式调用所有BeanPostProcessor,前后两次,形成增强链。
4.4 参考资料
五、MyBatis TypeHandler 源码剖析
5.1 类型适配环节拆解
1. setParameter
方法签名
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
内部逻辑
- Java对象类型 -> JDBC参数
- 负责将Java类型转为JDBC驱动支持的类型
源码片段
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
案例:枚举转数据库int
public void setParameter(PreparedStatement ps, int i, OrderStatus parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter.getCode());
}
速记口诀
“Java转JDBC,写入参数需适配。”
2. getResult
方法签名
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
内部逻辑
- JDBC类型 -> Java对象类型
- 负责将数据库结果集转换为业务对象
源码片段
OrderStatus getResult(ResultSet rs, String columnName) throws SQLException {
int code = rs.getInt(columnName);
return OrderStatus.of(code);
}
速记口诀
“结果转Java,类型安全要把握。”
5.3 行级源码剖析
以MyBatis的BaseTypeHandler为例:
// org.apache.ibatis.type.BaseTypeHandler
@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("...");
}
ps.setNull(i, jdbcType.TYPE_CODE);
} else {
setNonNullParameter(ps, i, parameter, jdbcType);
}
}
注释:空值处理后委托setNonNullParameter,子类只需实现非空逻辑。
5.4 参考资料
六、调试与优化技巧
- HandlerInterceptor:
- 日志打印每个环节,链路顺序可通过
@Order
注解控制
- 日志打印每个环节,链路顺序可通过
- BeanPostProcessor:
- 仅对指定Bean增强,避免全局副作用
- TypeHandler:
- 明确类型映射,开启MyBatis日志追踪参数与结果
七、业务场景举例
- HandlerInterceptor:API网关统一鉴权、灰度流量打标
- BeanPostProcessor:自动注入分布式事务代理、统一监控埋点
- TypeHandler:数据库JSON字段与Java对象互转、加密字段自动解密
八、设计模式与架构演进
- 责任链模式:拦截器、处理器链式调用
- 模板方法模式:抽象类提供默认实现,子类重写核心逻辑
- 策略/适配器模式:TypeHandler多类型适配
- 分布式演进:拦截器链与处理器链可分布式部署,支持幂等、降级
九、权威资料与参考文献
- Spring HandlerInterceptor 源码
- Spring BeanPostProcessor 源码
- MyBatis TypeHandler 源码
- Spring官方文档
- MyBatis官方文档
- Effective Java(第三版)
- 设计模式:可复用面向对象软件的基础
十、系统性总结&归纳
通过对Spring HandlerInterceptor、BeanPostProcessor、MyBatis TypeHandler源码主流程的每个环节细化剖析,我们掌握了多接口+抽象类+责任链/策略/模板方法等主流设计模式的精髓。理解其具体方法、源码实现、业务场景、扩展性与分布式演进,有助于在实际开发中打造高可维护、高扩展、高性能的企业级系统。
终极口诀:
“前拦截,后增强,类型适配链;接口分明易扩展,源码深究见真章。”
如需完整业务代码,请参考上述官方GitHub源码与文档。