核心类 ThreadLocal
、HandlerInterceptor
、HandlerMethodArgumentResolver
1. ThreadLocal
2. WebMvcConfigurer
- addArgumentResolvers
3. HandlerMethodArgumentResolver
- supportsParameter
- resolveArgument
-
ThreadLocal
:可以理解为一个线程安全的Map。// 用户上下文 public class UserContext { private static ThreadLocal<TUser> userThreadLocal = new ThreadLocal<>(); public static void setUser(TUser tUser) { userThreadLocal.set(tUser); } public static TUser getUser() { return userThreadLocal.get(); } public static void remove(){ userThreadLocal.remove(); } }
-
HandlerInterceptor
:接口是Spring MVC
中的一种拦截器,用于在请求处理过程中进行预处理和后处理操作。HandlerInterceptor接口定义了三个方法,分别是: 1. `preHandle`: 在请求处理方法之前执行。这允许你在请求被处理之前执行一些操作,例如验证用户身份或日志记录。 - 一般我们接口都需要带token,会获取用户信息。 - 我们可以在`preHandle`方法中,放入user。 - UserContext.setUser(tUser); 2. `postHandle`: 在请求处理方法之后,视图渲染之前执行。这允许你在返回响应之前修改模型数据或视图。 3. `afterCompletion`: 在整个请求处理完成之后执行。这是在响应已经被发送给客户端之后执行的方法,通常用于清理资源或执行一些最终的操作。 - 请求结束之后,可以使用 UserThreadLocal.remove(); - 好处:避免内存泄露。 - 原因:ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,弱引用的特点是,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉。
-
将
HandlerInterceptor
注册进WebMvcConfigurer
@Configuration public class WebMVCConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addCorsMappings(CorsRegistry registry) { } @Override public void addInterceptors(InterceptorRegistry registry) { // 将处理器拦截器注册进WebMvcConfig registry.addInterceptor(loginInterceptor); } }
-
UserThreadLocal
总结1. 在本次请求中,任何地方用到user的地方,我们都可以使用:SysUser sysUser = UserThreadLocal.get();
-
思考
1. 每次获取user对象,都需要写:SysUser sysUser = UserThreadLocal.get(); 2. 能不能不写?
-
解决办法:
HandlerMethodArgumentResolver
-处理方法参数解析器@Component public class UserArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { Class<?> parameterType = parameter.getParameterType(); // 只有返回`true`时,`resolveArgument`方法才会执行。 return parameterType == TUser.class; } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { return UserContext.getUser(); } }
-
将
UserArgumentResolver
注册进WebMvcConfigurer
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private UserArgumentResolver userArgumentResolver; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(userArgumentResolver); } }
-
代码实例
// 这时候,请求不需要传user参数,我们的接口也能获取到user @Slf4j @GetMapping(value = "/test") public void test(TUser user) { log.info("user:{}",user); }
-
总结
1. 每次请求过来,都会经过`HandlerMethodArgumentResolver`-方法参数解析器,当参数类型为,`TUser`时,会从`ThreadLocal`中获取`TUser`,赋值给接口中的`user`参数。