Javaweb中过滤器、监听器、拦截器的区别



拦截器与过滤器的区别

  1. 拦截器是基于 java 的反射机制的,而过滤器是基于函数回调。
  2. 拦截器不依赖与 servlet 容器,过滤器依赖与 servlet 容器。
  3. 拦截器只能对 action 请求起作用,而过滤器则可以对几乎所有的请求起作用。
  4. 拦截器可以访问 action 上下文、值栈里的对象,而过滤器不能访问。
  5. 在 action 的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次拦截器的代码实现。
  6. Filter 基于回调函数,我们需要实现的 filter 接口中 doFilter 方法就是回调函数,而 interceptor 则基于 java 本身的反射机制,这是两者最本质的区别。
  7. Filter 是依赖于 servlet 容器的,即只能在 servlet 容器中执行,很显然没有 servlet 容器就无法来回调 doFilter 方法。而 interceptor 与 servlet 容器无关。
  8. Filter 的过滤范围比 Interceptor 大,Filter 除了过滤请求外通过通配符可以保护页面,图片,文件等等, 而 Interceptor 只能过滤请求。
  9. Filter 的过滤例外一般是在加载的时候在 init 方法声明,而 Interceptor 可以通过在 xml 声明是 guest 请求还是 user 请求来辨别是否过滤。

概念

servlet

servlet 是一种运行服务器端的 java 应用程序,具有独立于平台和协议的特性,
可以动态生成 web 页面,它工作在客户端请求与服务器响应的中间层;

生命周期

1
2
3
4
5
6
servle的生命周期开始于被装入web服务器的内存中,并在web服务终止或者重新装入servlet的时候结束;
servlet一旦被装入web服务器,一般不会从web服务器内存中删除;直到web服务器关闭;
  装入:启动服务器时加载servlet的实例;
  初始化:web服务器接收到请求时,或者两者之间的某个时刻启动,调用init()
  调用:从第一次到以后的多次访问,都只调用doGet()或doPost()方法;
  销毁;停止服务器时调用destroy()方法,销毁实例;

过滤器:filter

过滤器是一个程序,它先于与之相关的 servlet 或 JSP 页面运行在服务器上。过滤器可附加到一个或多个 servlet 或 JSP 页面上,并且可以检查进入这些资源的请求信息。在这之后,过滤器可以作如下的选择:

  1. 以常规的方式调用资源(即,调用 servlet 或 JSP 页面)。
  2. 利用修改过的请求信息调用资源。
  3. 调用资源,但在发送响应到客户机前对其进行修改。
  4. 过滤掉非法 url,阻止该资源调用,代之以转到其他的资源,返回一个特定的状态代码或生成替换输出。
  5. 去除掉一些非法字符(聊天室经常用到的,一些骂人的话)
  6. 基于函数回调来实现的

生命周期

1
2
3
4
需要实现javax.servlet包的Filter接口的三个方法init(),doFilter(),destroy();
  加载:启动服务器时加载过滤器的实例,并调用init()方法;
  调用:每次请求的时候只调用方法doFilter()进行处理;
  销毁:服务器关闭前调用destroy()方法,销毁实例;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
MyCharsetFilter.java 编码过滤器
package ...;
import ...;
// 主要目的:过滤字符编码;其次,做一些应用逻辑判断等.
// Filter跟web应用一起启动
// 当web应用重新启动或销毁时,Filter也被销毁
public class MyCharsetFilter implements Filter {
private FilterConfig config = null;
public void destroy() {
System.out.println("MyCharsetFilter准备销毁...");
}

public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
// 强制类型转换
HttpServletRequest request = (HttpServletRequest)arg0;
HttpServletResponse response = (HttpServletResponse)arg1;
// 获取web.xm设置的编码集,设置到Request、Response中
request.setCharacterEncoding(config.getInitParameter("charset"));
response.setContentType(config.getInitParameter("contentType"));
response.setCharacterEncoding(config.getInitParameter("charset"));
// 将请求转发到目的地
chain.doFilter(request, response);
}

public void init(FilterConfig arg0) throws ServletException {
this.config = arg0;
System.out.println("MyCharsetFilter初始化...");
}
}

MyCharsetFilter.java 在 web.xml 中配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<filter>
<filter-name>filter</filter-name>
<filter-class>dc.gz.filters.MyCharsetFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>contentType</param-name>
<param-value>text/html;charset=UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<!-- * 代表截获所有的请求 或指定请求/test.do /xxx.do -->
<url-pattern>/*</url-pattern>
</filter-mapping>

拦截器:interceptor

拦截器是基于 JAVA 的反射机制对过滤器更加细化的应用,不仅可以应用在service 方法前后还可以应用到其他方法的前后

生命周期

1
2
加载配置文件后初始化拦截器,当有对action的请求的时候,
调用interceptor方法,最后也是根据服务器停止进行销毁

代码

struts中的配置

1
2
3
4
5
6
7
8

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("方法调用前,可以执行一段代码" + method.getName());
result = method.invoke(this.targetObj, args);
System.out.println("方法调用后,可以执行一段代码 " + method.getName());
return result;
}

如果是Spring框架,我们可以直接继承HandlerInterceptorAdapter.java这个抽象类,来实现我们自己的拦截器。(HandlerInterceptorAdapter继承了抽象接口HandlerInterceptor。)

实现了用户登录认证的拦截功能,如果当前用户没有通过认证,会报403错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package org.springframework.web.servlet.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UserRoleAuthorizationInterceptor extends HandlerInterceptorAdapter{
// 字符串数组,用来存放用户角色信息
private String[] authorizedRoles;
public final void setAuthorizedRoles(String[] authorizedRoles){
this.authorizedRoles = authorizedRoles;
}


// 在业务处理器处理请求之前被调用
public final boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException, IOException{
if (this.authorizedRoles != null) {
for (int i = 0; i < this.authorizedRoles.length; ++i) {
if (request.isUserInRole(this.authorizedRoles[i])) {
return true;
}
}
}
handleNotAuthorized(request, response, handler);
return false;
}

protected void handleNotAuthorized(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException, IOException{
// 403表示资源不可用。服务器理解用户的请求,但是拒绝处理它,通常是由于权限的问题
response.sendError(403);
}
}

详细可以参考我的这篇文章

监听器:listener

通过 listener 可以监听 web 服务器中某一执行动作,并根据其要求作出相应的响应。
在 application,session,request 三个对象创建消亡或者往其中添加修改删除属性时自动执行代码的功能组件,也可以做一些初始化的内容添加工作、设置一些基本的内容

生命周期

1
web.xml的加载顺序是:context-param -> listener -> filter -> servlet

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
MyServletContextListener.java
package dc.gz.listeners;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.dbcp.BasicDataSource;

/**
* Web应用监听器
*/
public class MyServletContextListener implements ServletContextListener {
// 应用监听器的销毁方法
public void contextDestroyed(ServletContextEvent event) {
ServletContext sc = event.getServletContext();
// 在整个web应用销毁之前调用,将所有应用空间所设置的内容清空
sc.removeAttribute("dataSource");
System.out.println("销毁工作完成...");
}

// 应用监听器的初始化方法
public void contextInitialized(ServletContextEvent event) {
// 通过这个事件可以获取整个应用的空间
// 在整个web应用下面启动的时候做一些初始化的内容添加工作
ServletContext sc = event.getServletContext();
// 设置一些基本的内容;比如一些参数或者是一些固定的对象
// 创建DataSource对象,连接池技术 dbcp
BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUrl("jdbc:mysql://localhost:3306/hibernate");
bds.setUsername("root");
bds.setPassword("root");
bds.setMaxActive(10);//最大连接数
bds.setMaxIdle(5);//最大管理数
// bds.setMaxWait(maxWait); 最大等待时间
// 把 DataSource 放入ServletContext空间中,
// 供整个web应用的使用(获取数据库连接)
sc.setAttribute("dataSource", bds);
System.out.println("应用监听器初始化工作完成...");
System.out.println("已经创建DataSource...");
}
}

web.xml中配置

1
2
3
4
<!-- 配置应用监听器  --> 
<listener>
<listener-class>dc.gz.listeners.MyServletContextListener</listener-class>
</listener>

注意

servlet,filter,listener 是配置到 web.xml 中,但 interceptor 不配置到 web.xml 中
struts 的拦截器配置到 struts。xml 中
spring 的拦截器配置到 spring.xml 中

java 过滤器、监听器、拦截器的区别
java web 拦截器和过滤器的区别
过滤器、监听器、拦截器的区别
Java三大器之拦截器(Interceptor)的实现原理及代码示例

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  1. © 2020 Liu Yang    湘ICP备20003709号

请我喝杯咖啡吧~

支付宝
微信