Grails 3.1.7集成Spring Security Core 3.1.1潜在内存泄漏问题咨询
我来帮你搞定这个Tomcat日志里的ThreadLocal泄漏报错,这种情况在旧版本的Grails和Spring Security组合里确实挺常见的——本质是Tomcat在应用重启/停止时,检测到有ThreadLocal没有被正确清理,导致Web应用的类加载器无法被回收,进而触发这个SEVERE级别的日志。
下面给你几个实用的解决思路,按优先级排序:
优先考虑升级依赖版本
你的Spring Security Core 3.1.1和Grails 3.1.7都是比较老的版本了,后续迭代已经修复了不少ThreadLocal相关的泄漏问题。建议先尝试升级Spring Security Core到适配Grails 3.1.x的最新兼容版本(比如3.2.0,记得要和Grails版本匹配,别跨版本太猛);如果项目允许,也可以考虑把Grails升级到3.3.x系列,这个版本更稳定,对Spring Security的兼容性也更好。检查Spring Security的自动清理机制
Spring Security默认会通过SecurityContextPersistenceFilter在请求结束后清理SecurityContextHolder里的ThreadLocal内容,但如果你的项目里有自定义过滤器、拦截器,或者请求处理中出现了未捕获的异常,可能会干扰这个清理流程。你可以排查下项目里的自定义Web组件,看看有没有在请求结束后没正确放行,或者覆盖了默认的清理逻辑。添加兜底的手动清理过滤器
如果暂时没法升级依赖,那可以自己加一个过滤器,在请求结束时强制清理SecurityContext,避免ThreadLocal残留。写个Groovy过滤器:import org.springframework.security.core.context.SecurityContextHolder import javax.servlet.* import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse class SecurityContextCleanupFilter implements Filter { @Override void init(FilterConfig filterConfig) throws ServletException {} @Override void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { chain.doFilter(request, response) } finally { // 不管请求成功还是失败,都强制清理上下文 SecurityContextHolder.clearContext() } } @Override void destroy() {} }然后在
grails-app/conf/spring/resources.groovy里注册这个Bean:beans = { securityContextCleanupFilter(SecurityContextCleanupFilter) }最后在
grails-app/conf/application.groovy里把这个过滤器加到Spring Security的过滤器链里,确保它在securityContextPersistenceFilter之后执行:grails.plugin.springsecurity.filterChain.chainMap = [ '/**': 'securityContextPersistenceFilter,securityContextCleanupFilter, ...' // 后面跟你原来的其他过滤器 ]排查异步任务的ThreadLocal使用
如果你的项目里用了异步处理(比如@Async注解),要注意Spring Security的上下文不会自动传递到异步线程里,而且异步线程结束后如果没手动清理ThreadLocal,就会导致泄漏。这种情况下,要么在异步方法的末尾手动调用SecurityContextHolder.clearContext(),要么自定义一个TaskExecutor来处理上下文的传递和自动清理。检查Tomcat的配置参数
虽然你不确定Tomcat版本,但不同版本的泄漏检测严格程度不一样,比如Tomcat 8.5+的检测会更敏感。你可以看看Tomcat的conf/context.xml里有没有配置antiResourceLocking="true"或者antiJARLocking="true",这些参数可能会影响类加载器的回收,尝试调整一下看看能不能缓解问题。
内容的提问来源于stack exchange,提问作者the_coding_cowboy

