Filter 由 Servlet 容器建立,不受 Spring 管理,@Autowired 失效導致 Service 為 null。提供三種手動獲取 Bean 方式與一種攔截器替代方案。
public class WeiXinFilter implements Filter {
@Autowired private UsersService usersService; // null!
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
Users u = usersService.queryByOpenid(openid); // NPE
}
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
ServletContext sc = request.getSession().getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sc);
if (ctx != null && usersService == null) {
usersService = ctx.getBean(UsersService.class);
}
// 後續業務邏輯...
}
public class WeiXinFilter implements Filter {
private UsersService usersService;
public void init(FilterConfig config) {
ServletContext sc = config.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sc);
if (ctx != null) usersService = ctx.getBean(UsersService.class);
}
// doFilter 中直接使用 usersService...
}
攔截器由 Spring 管理,支援 @Autowired,生命週期方法 preHandle/postHandle/afterCompletion 對應 Filter 鏈。
@Component
public class WeiXinInterceptor implements HandlerInterceptor {
@Autowired private UsersService usersService;
@Override public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) {
// 預處理邏輯,返回 false 截斷請求
return true;
}
@Override public void postHandle(...) { /* 後處理 */ }
@Override public void afterCompletion(...) { /* 清理 */ }
}
配置攔截路徑:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.example.interceptor.WeiXinInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
ContextLoaderListener 啟動時建立根 WebApplicationContext,並存入 ServletContext 屬性 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。DispatcherServlet 建立子 WebApplicationContext,父子關係可訪問根容器 Bean。WebApplicationContextUtils.getWebApplicationContext(servletContext) 即從 ServletContext 取出根容器。public class WeiXinFilter implements Filter {
private UsersService usersService;
// init() 獲取 Bean...
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
// ... 微信 UA 判斷、Cookie 解密獲取 openid ...
// 手動獲取 Bean(若 init 未獲取)
ServletContext sc = request.getSession().getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sc);
if (ctx != null && usersService == null) usersService = ctx.getBean(UsersService.class);
Users user = usersService.queryByOpenid(openid);
// ... 登入狀態檢查、轉發登入頁或放行 ...
chain.doFilter(request, response);
}
}