如何l利用`ThreadLocal`、`HandlerInterceptor`、`HandlerMethodArgumentResolver`来完成代码优化
发布时间 2023-11-16 17:10:42作者: zzusjw
核心类 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 的弱引用,弱引用的特点是,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉。
-
@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();
}
}
-
@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`参数。