能否设置OpenEntityManagerInView执行顺序使其优先于所有自定义过滤器?
根本原因
OpenEntityManagerInViewInterceptor 是 Spring MVC 层面的拦截器,只有请求进入 DispatcherServlet 后才会触发执行,天然晚于所有 Servlet 过滤器的执行时机,因此调整自定义过滤器的 @Order 注解无法让拦截器提前到过滤器之前运行。
你之前使用 @Order(Ordered.LOWEST_PRECEDENCE) 无效还有两个额外原因:一是 Ordered.LOWEST_PRECEDENCE 对应最大的优先级数值,代表优先级最低,只会让你的过滤器更晚执行但依旧在拦截器之前;二是不同层面的组件(过滤器、MVC拦截器)的Order配置互不生效。
推荐解决方案:改用过滤器级别的EntityManager生命周期管理
将默认的 OpenEntityManagerInViewInterceptor 替换为同功能的 OpenEntityManagerInViewFilter,后者是Servlet过滤器级别的实现,可以通过调整优先级保证在所有自定义过滤器之前执行,具体操作步骤如下:
- 关闭默认的拦截器自动配置
在 application 配置文件中添加配置:
spring.jpa.open-in-view=false
- 手动注册
OpenEntityManagerInViewFilter并设置最高优先级
@Configuration public class FilterConfig { @Bean public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() { return new OpenEntityManagerInViewFilter(); } @Bean public FilterRegistrationBean<OpenEntityManagerInViewFilter> emFilterRegistration() { FilterRegistrationBean<OpenEntityManagerInViewFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(openEntityManagerInViewFilter()); // 设置最高优先级,保证最先执行 registration.setOrder(Ordered.HIGHEST_PRECEDENCE); registration.addUrlPatterns("/*"); return registration; } }
- 调整自定义AuthFilter的优先级
给你的AuthFilter设置大于Ordered.HIGHEST_PRECEDENCE的Order值即可,比如:
@Component @Order(Ordered.HIGHEST_PRECEDENCE + 1) public class AuthFilter extends OncePerRequestFilter { // 原有逻辑不变 }
额外优化建议
完成上述配置后,你可以去掉AuthFilter上的@Transactional注解:此时请求进入AuthFilter时,OpenEntityManagerInViewFilter已经完成EntityManager的初始化并绑定到当前线程,Service层的@Transactional会直接复用已有的EntityManager,事务提交后不会关闭EntityManager,EntityManager会在整个请求结束后由OpenEntityManagerInViewFilter统一关闭,彻底避免两次创建关闭会话的问题。
内容的提问来源于stack exchange,提问作者abhi_awake

