什么是拦截器与过滤器与监听器的区别是什么?
拦截器、过滤器和监听器是在Java Web开发中常用的三种组件,它们在不同层面上对请求和响应进行处理,但有一些区别:
拦截器(Interceptor):拦截器是一种在方法调用前后、异常抛出前后等关键节点进行拦截处理的组件。在Java中,拦截器通常用于AOP(面向切面编程)中,可以对方法进行增强或添加额外的逻辑。拦截器一般是针对特定的方法或类进行拦截,可以在方法执行前后做一些处理,如日志记录、权限验证等。
过滤器(Filter):过滤器是一种用于在请求到达Servlet之前或响应返回给客户端之前进行预处理或后处理的组件。过滤器可以对请求和响应进行拦截和修改,常用于实现一些通用的功能,如字符编码转换、请求参数处理、权限验证等。过滤器是基于Servlet规范的,可以对整个应用的请求进行过滤。
监听器(Listener):监听器是一种用于监听Web应用中事件发生的组件。通过监听器,可以在特定事件发生时执行相应的逻辑,如应用启动和关闭、会话创建和销毁、属性变化等。监听器可以用于在应用运行期间进行一些全局性的操作,如初始化一些资源、记录应用的状态等。
总结来说,拦截器主要用于方法调用前后的拦截处理,过滤器主要用于请求和响应的预处理和后处理,监听器主要用于监听应用中的事件发生。它们在功能上有所重叠,但在使用场景和具体实现上有一些区别。
监听器、过滤器和拦截器的执行顺序
过滤器→监听器→拦截器
监听器(Listener)的执行顺序:
应用启动时,先执行ContextListener(ServletContextListener)的contextInitialized()方法。
当会话(Session)创建时,执行HttpSessionListener的sessionCreated()方法。
当会话(Session)销毁时,执行HttpSessionListener的sessionDestroyed()方法。
当属性变化时,执行HttpSessionAttributeListener的attributeAdded()、attributeRemoved()、attributeReplaced()方法。
应用关闭时,执行ContextListener的contextDestroyed()方法。
过滤器(Filter)的执行顺序:
根据在web.xml中配置的顺序,依次执行每个过滤器的doFilter()方法。
如果有多个过滤器,按照配置的顺序依次执行,直到最后一个过滤器执行完毕后,再执行Servlet的service()方法。
拦截器(Interceptor)的执行顺序:
根据拦截器的配置顺序,依次执行每个拦截器的拦截方法(intercept())。
如果有多个拦截器,按照配置的顺序依次执行,直到最后一个拦截器执行完毕后,再执行目标方法。
需要注意的是,监听器是在应用启动和关闭、会话创建和销毁、属性变化等事件发生时触发执行;过滤器是在请求到达Servlet之前和响应返回给客户端之前进行预处理和后处理;拦截器是在方法调用前后进行拦截处理。它们之间的执行顺序是根据配置的顺序来确定的。
分页拦截器底层的执行原理
PageHelper的底层拦截器核心代码主要是通过实现MyBatis的Interceptor接口来实现的。下面是一个简化的示例代码,展示了PageHelper拦截器的核心逻辑:
public class PageInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取原始的SQL语句
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
BoundSql boundSql = mappedStatement.getBoundSql(invocation.getArgs()[1]);
String originalSql = boundSql.getSql();
// 判断原始SQL是否需要进行分页处理
if (originalSql.contains("SELECT")) {
// 获取分页参数
Page<?> page = PageHelper.getLocalPage();
if (page != null) {
// 修改原始SQL语句,添加分页逻辑
String pageSql = generatePageSql(originalSql, page);
boundSql.setSql(pageSql);
}
}
// 继续执行原始的查询方法
return invocation.proceed();
}
// 生成分页SQL语句
private String generatePageSql(String originalSql, Page<?> page) {
// 根据数据库类型生成对应的分页SQL语句
String dialect = getDatabaseDialect();
String pageSql = dialect + " LIMIT " + page.getStartRow() + ", " + page.getPageSize();
return pageSql;
}
// 获取数据库方言
private String getDatabaseDialect() {
// 根据配置获取数据库方言
return "MySQL"; // 示例代码中使用MySQL作为数据库
}
// 其他方法省略...
}