Java中Servlet过滤器和Spring拦截器的关系以及区别

最近项目在用过滤器和拦截器,顺便整理下这两个组件的关系以及区别;
前言
先说下这两个组件在项目中的使用场景吧,我们的项目采用的微服务架构

  1. 网关层采用的javax.servlet的Filter过滤器进行
    统一登录认证和鉴权或者IP、URL黑白名单验证;
  2. 各个服务层通过Spring的Interceptor拦截器进行
    用户信息的解析绑定到当前请求线程应用程序上下文的BaseInfo以便后续的业务逻辑使用;
    当前请求参数和响应的格式化打印;

直接上图这两个组件的关系
Java中Servlet过滤器和Spring拦截器的关系以及区别_第1张图片
区别点:
过滤器是基于J2EE标准Servlet规范的函数回调,拦截器是基于Java的反射机制;
过滤器依赖servlet容器应用于Java web程序,拦截器不依赖servlet容器,可在非web程序中使用;
过滤器是包裹着拦截器的组件;
过滤器(普通的)无法直接获取Spring容器的bean,拦截器可以直接使用Spring容器的bean并进行相关业务处理;

源码分析:
过滤器Filter 项目中采用的zuul组件因此下面代码是基于ZuulFilter的

/**
 * token过滤器,校验token必输,token不能为空
 * url过滤
 * @author
 */
@Component
@EnableConfigurationProperties(IgnoreUriConfig.class)
public class AccessTokenFilter extends ZuulFilter {
     
    private static Logger log = LoggerFactory.getLogger(AccessTokenFilter2.class);
    private static final String CHARSET_UTF8 = "UTF-8";
    @Autowired
    private IgnoreUriConfig ignoreUriConfig;
    @Autowired
    private AuthFeignClient authFeignClient;
    @Value("${jwt.key}")
    private String jwtSignKey;
    @Value("${jwt.valid}")
    private String valid;
    /*
     * 过滤器的具体逻辑。
     * @see com.netflix.zuul.IZuulFilter#run()
     */
    @Override
    public Object run() {
     
        // 请求上下文
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
        String token = request.getHeader("Authorization");
        // 需要忽略的uri验证
        if (!ObjectUtils.isEmpty(ignoreUriConfig.getList())) {
     
            if (ignoreUriConfig.getList().contains(request.getRequestURI())) {
     
                return null;
            }
        }
        // 校验token是否空
        if (ObjectUtils.isEmpty(token)) {
     
            log.warn("token is empty");
            buildResponse(ctx, 10016, "token is empty");
            return null;
        }
        token = StringUtils.substringAfterLast(token, " ");
        if (!checkToken(token)) {
     
            log.warn("token expire or invalid");
            buildResponse(ctx, 10017, "token expire or invalid");
            return null;
        }
        try {
     
            Claims parseJWT = TestJWT.parseJWT(token.toString(), jwtSignKey);
            log.debug(new Gson().toJson(parseJWT).toString());
        } catch (Exception e) {
     
            buildResponse(ctx, 10018, "token invalid:" + e.getMessage());
        }
        log.info("ok");
        return null;
    }
    /**
    * 构建响应内容
    */
    private void buildResponse(RequestContext ctx, int code, String message) {
     
        try {
     
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(200);
            HttpServletResponse response = ctx.getResponse();
            response.setContentType("application/json;charset=UTF-8");
            response.setCharacterEncoding(CHARSET_UTF8);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", code);
            jsonObject.put("message", message);
            response.getWriter().write(jsonObject.toJSONString());
        } catch (Exception e) {
     
        }
    }
    /**
     * token有效返回true
     * token无效过期返回false
     * @return
     */
    private boolean checkToken(String token) {
     
        AuthTokenRequest authTokenRequest = new AuthTokenRequest();
        authTokenRequest.setToken(token);
        BaseResponse response = authFeignClient.verify(authTokenRequest);
        if (response.isSuccess()) {
     
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }
    /*
     * 这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
     * @see com.netflix.zuul.IZuulFilter#shouldFilter()
     */
    @Override
    public boolean shouldFilter() {
     
        return true;
    }
    @Override
    public int filterOrder() {
     
        return 0;
    }
    /*
     * (non-Javadoc) pre:路由之前 routing:路由之时 post: 路由之后 error:发送错误调用
     * @see com.netflix.zuul.ZuulFilter#filterType()
     */
    @Override
    public String filterType() {
     
        return "pre";
    }
}

拦截器Interceptor

/**
 * 服务层拦截器
 * @author
 */
public class ServiceInterceptor implements HandlerInterceptor {
     
    private static final Logger logger = LoggerFactory.getLogger(ServiceInterceptor2.class);
    // spring bean的方法执行之前拦截处理
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
     
        String authorization = httpServletRequest.getHeader("Authorization");
        String token = StringUtils.substringAfterLast(authorization, " ");
        try {
     
        	// 解析token,获取信息,设置到应用上下文中
            if (StringUtils.isNotBlank(token)) {
     
                Claims claims = JWTHelper.parseJWT(token, "999999");
                UserInfo userInfo = new UserInfo();
                try {
     
                    userInfo.setUserId(ObjectUtils.toString(claims.get("userId")));
                } catch (Exception e) {
     
                    logger.error("设置userId异常:{}", e);
                }
                /**
                 * 设置公共参数
                 */
                userInfo.setUserNo(claims.get("userNo") + "");
                //将UserInfo放入上下文中
                UserInfoContext.setUser(userInfo);
            }
        } catch (Exception e) {
     
            // 解析不到认证标识
            logger.error("解析认证标识异常:authorization:{},exception:{}", authorization, e);
            return false;
        }
        return true;
    }
    /**
     * 用户信息上下文
     */
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
     
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
     
        // 清理threadLocal,防止内存泄漏
        UserInfoContext.clean();
    }
}

-------------欢迎各位留言交流,如有不正确的地方,请予以指正。【Q:981233589】

你可能感兴趣的:(源码研究,J2EE,springcloud,过滤器,spring,java,filter,拦截器)