Este é um problema que encontrei durante uma entrevista há pouco tempo. Fiquei muito confuso na época. Embora os dois solteiros não estivessem completos, eles provavelmente sabiam que a solicitação poderia ser interceptada. Foi uma dor de cabeça compará-los.
Na verdade, fui aprender uma onda depois da entrevista antes, mas não a resumi a tempo naquela época, vou resumir agora, para não encontrar esses problemas no futuro e esquecer.
Para entender esse tipo de problema, a memorização mecânica pode ser útil na hora e quase será esquecida depois de um tempo. Para realmente lembrar, temos que fazer isso.
Uso de Filtro
Primeiro, para usar o Filtro, você deve implementar a interface javax.servlet.Filter:
public interface Filter {
//web应用加载进容器,Filter对象创建之后,执行init方法初始化,用于加载资源,只执行一次。
public default void init(FilterConfig filterConfig) throws ServletException {}
//每次请求或响应被拦截时执行,可执行多次。
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
//web应用移除容器,服务器被正常关闭,则执行destroy方法,用于释放资源,只执行一次。
public default void destroy() {}
}
- Init e destroy são os métodos padrão e a classe de implementação não precisa ser implementada.
- doFilter deve ser implementado, ou seja, como um filtro, doFilter deve ser definido.
- O objeto FilterChain passado no método doFlilter é usado para chamar o próximo filtro.
Uso de interceptores
public interface HandlerInterceptor {
//拦截handler的执行 --> 在HanlerMapping决定适合的handler之后,[在HandlerAdater调用handler之前执行。]
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception { return true;
} //拦截handler的执行 --> [在HandlerAdapter调用handler之后],在DispatcherServlet渲染视图之前执行
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception { } //视图渲染后调用,且只有preHandle结果为true,才会调用
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception { }}
//DispatcherServlet
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return; //遍历所有的interceptors,调用preHandle方法,只有返回true,才能进行下去
}
// 这里也就是处理Contrller
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//视图渲染
applyDefaultViewName(processedRequest, mv);
//视图渲染之后调用
mappedHandler.applyPostHandle(processedRequest, response, mv);
Qual é a diferença entre um filtro e um interceptor?
1. O princípio de realização é diferente
- A implementação do filtro é baseada na função de retorno de chamada
- O interceptor é implementado com base no mecanismo de reflexão Java [proxy dinâmico].
Dois, o escopo de uso é diferente
- O filtro é uma especificação de Servlet e precisa implementar a interface javax.servlet.Filter.O uso do Filtro precisa depender de contêineres como o Tomcat.
- O interceptor é um componente Spring, definido no pacote org.springframework.web.servlet, gerenciado pelo contêiner Spring [com métodos de processamento de ciclo de vida mais ricos, refinado e capaz de usar recursos Spring] e não depende do Tomcat Espere pelo contêiner.
Três, o tempo de disparo é diferente
Este parágrafo pode ser encontrado na anotação da classe HandlerInterceptor, o tempo de disparo dos dois é diferente:
- Filtro: Processe a solicitação antes ou depois de entrar no servlet.
- Interceptor: A solicitação é processada antes e depois do manipulador [Controlador].
Quarto, a ordem de execução é diferente
Quando os filtros e interceptores são configurados:
MyFilter1 前
MyFilter2 前
MyInterceptor1 在Controller前执行
MyInterceptor2 在Controller前执行
controller方法执行...
MyInterceptor2 Controller之后,视图渲染之前
MyInterceptor1 Controller之后,视图渲染之前
MyInterceptor2 视图渲染完成之后执行
MyInterceptor1 视图渲染完成之后执行
MyFilter2 后
MyFilter1 后
- Ordem dos filtros
Cada vez que o objeto da cadeia é passado para obter o efeito do retorno de chamada da interface final:
- Ordem do interceptor
preHandle1 -> preHandle2 -> [Controlador] -> postHandle2 -> postHandle1 -> afterCompletion2 -> afterCompletion1 preHandle está na ordem de registro, e os dois últimos são opostos à ordem de registro.
- Se o preHandle de um interceptor for falso, todos os interceptores subsequentes não serão executados.
- Se o preHandle de um interceptor for verdadeiro, o triggerAfterCompletion desse interceptor será executado.
- Somente se todos os interceptores preHandler forem verdadeiros, ou seja, forem executados normalmente, o postHandle será executado.
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i]; //一旦当前拦截器preHandle的返回值为false,那么从上一个可用的拦截器的afterCompletion开始
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false; //这里返回false意为 后续不进行下去了。
} this.interceptorIndex = i;//interceptorIndex初始化为-1,只有当前拦截器preHandle为true,才会赋值当前的i。
} } return true;
}void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv);
} }}void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); for (int i = this.interceptorIndex; i >= 0; i--)
}
Quinto, a sequência de execução do controle é diferente
Ambos usam a ordem de registro por padrão. Se você deseja controlar a ordem de execução, a forma é um pouco diferente:
- Se você quiser forçar a mudança do filtro, você pode usar a anotação @Order.
- Se o interceptor usa o método order ()
@Order(2)
@Component
public class MyFilter1 implements Filter {}
@Component
public class WebAdapter implements WebMvcConfigurer {
@Autowired
MyInterceptor1 myInterceptor1; @Autowired
MyInterceptor2 myInterceptor2; @Override
public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myInterceptor1).addPathPatterns("/**").order(2);
registry.addInterceptor(myInterceptor2).addPathPatterns("/**").order(1);
}}
Resumindo
- Em princípio, o filtro é baseado na implementação de retorno de chamada e o interceptor é baseado no proxy dinâmico.
- Granularidade de controle: filtros e interceptores podem realizar a função de interceptação de solicitações, mas há uma grande diferença na granularidade de interceptação, e a granularidade do interceptor para controle de acesso é mais precisa.
- Cenários de uso: os interceptores são frequentemente usados para verificação de permissão, registros de log, etc., os filtros são usados principalmente para filtrar parâmetros inválidos em solicitações e verificação de segurança.
- Dependente do container: O filtro depende do container Servlet e está limitado à web, enquanto o interceptor depende do framework Spring e pode usar os recursos do framework Spring, não se limitando à web.
- Tempo de acionamento: O filtro é executado antes e depois do servlet, e o interceptor é executado antes e depois do manipulador. Agora, a maioria dos aplicativos da web são baseados em Spring, e o interceptor é mais detalhado.
Se você acha que este artigo é útil para você, clique para apoiá-lo.
Você também pode acompanhar minha conta pública, há mais artigos técnicos sobre produtos secos e informações relacionadas sobre ela, todos aprendem e progridem juntos!