首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java Filter 中注入 Spring Service 失敗解決方案:三種獲取 Bean 方式與攔截器替代方案

     編輯:Java 綜合教學

Java Filter 中注入 Spring Service 失敗解決方案

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
    }
}

方案一:在 doFilter 中從 WebApplicationContext 手動查找

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);
    }
    // 後續業務邏輯...
}

方案二:在 init() 階段一次性獲取並快取

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 MVC HandlerInterceptor(推薦)

攔截器由 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>

原理補充:WebApplicationContext 與 ServletContext 關係

  • ContextLoaderListener 啟動時建立根 WebApplicationContext,並存入 ServletContext 屬性 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。
  • DispatcherServlet 建立子 WebApplicationContext,父子關係可訪問根容器 Bean。
  • WebApplicationContextUtils.getWebApplicationContext(servletContext) 即從 ServletContext 取出根容器。

完整 Filter 範例(含微信瀏覽器判斷、OpenID 解密、登入攔截)

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);
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved