目录
监听器配置流程(以ContextLoaderListener为例)
监听器、过滤器、拦截器的介绍
过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
拦截器:
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。
监听器:
监听器详解地址
web监听器是一种Servlet中的特殊的类,它们能帮助开发者监听web中的特定事件,实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化;
监听器的说明
监听器的用途
- 通常使用Web监听器做以下的内容:
- 统计在线人数,利用HttpSessionLisener
- 加载初始化信息:利用ServletContextListener
- 统计网站访问量
- 实现访问监控
监听器实现的接口
servlet的监听接口
- ServletContextListener监听web应用的启动和关闭
- ServletContextAttributeListener监听ServletContext范围内属性的改变
- ServletRequestListener监听用户的请求
- ServletRequestAttributeListener监听ServletRequest范围内(request)内属性的变化
- HttpSessionListener监听用户session的开始和结束
- HttpSessionAttributeListener监听HttpSession范围内session内属性的改变。
springmvc的监听器
ContextLoaderListener(实现ServletContextListener)用于加载spring容器的配置文件。
监听器配置流程(以ContextLoaderListener为例)
web.xml文件
<!--加载spring容器的配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/config/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/config/dispatcher-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
注意:
- dispatcher-context.xml主要是spring mvc里面的,控制器、拦截uri转发view。
- ApplicationContext.xml 是spring 全局配置文件,用来控制spring 特性
- 一个bean如果在两个文件中都被定义了(比如两个文件中都定义了component scan扫描相同的package), spring会在application context和 servlet context中都生成一个实例,他们处于不同的上下文空间中,他们的行为方式是有可能不一样的。
- 如果在application context和 servlet context中都存在同一个 @Service 的实例, controller(在servlet context中) 通过 @Resource引用时, 会优先选择servlet context中的实例。
最好的方法是:在applicationContext和dispatcher-servlet定义的bean最好不要重复, dispatcher-servlet最好只是定义controller类型的bean。
过滤器的说明
过滤器的用途
过滤特定请求资源、请求信息和响应信息。一个请求来到时,web容器会判断是否有过滤器与该信息资源相关联,如果有则交给过滤器处理,然后再交给目标资源,响应的时候则以相反的顺序交给过滤器处理,最后再返回给用户浏览器。一个filter 包括:
- 在servlet被调用之前截获;
- 在servlet被调用之前检查servlet request;
- 根据需要修改request头和request数据;
- 根据需要修改response头和response数据;
- 在servlet被调用之后截获.
过滤器实现的接口
public interface Filter {
void init(FilterConfig var1) throws ServletException;
void doFilter(ServletRequest var1, ServletResponse var2,
FilterChain var3) throws IOException, ServletException;
void destroy();
}
过滤器的配置流程
web.xml文件
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!--过滤的url地址-->
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
拦截器的说明
拦截器的用途
- 乱码问题:用request,response参数去设置编码;
- 解决权限验证问题(是否登陆,取session对象查看);
拦截器与过滤器的区别
- 拦截器Interceptor依赖于框架容器,基于反射机制,只过滤请求;
- 过滤器Filter依赖于Servlet容器,基于回调函数,过滤范围大;
拦截器实现接口
- 自定义一个实现了Interceptor接口的类,或者继承抽象类AbstractInterceptor。
- 在配置文件中注册定义的拦截器。
- 在需要使用Action中引用上述定义的拦截器,为了方便也可以将拦截器定义为默认的拦截器,这样在不加特殊说明的情况下,所有的Action都被这个拦截器拦截。
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor{
// 在业务处理器处理请求之前被调用
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
return true;
}
// 在业务处理器处理请求完成之后,生成视图之前执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception{
}
// 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception{
}
}
拦截器的配置
在dispatch-servlet.xml中配置
<!--配置拦截器, 多个拦截器,顺序执行 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
<mvc:mapping path="/**"/>
<bean class="com.cckj.util.auth.AuthInterceptor"></bean>
</mvc:interceptor>
<!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>
了解监听器、过滤器、servlet的启动顺序
问题描述:
在
filter中使用
@Autowired或@Resource注入
bean
时注入失败,bean
一直为空。
web应用启动的顺序是:listener->filter->servlet,先初始化listener,然后再来就filter的初始化,再接着才到我们的dispathServlet的初始化,因此,当我们需要在filter里注入一个注解的bean时,就会注入失败,因为filter初始化时,注解的bean还没初始化,没法注入。
解决方法
/**
* 解决Filter中注入Bean失败
*/
@Slf4j
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
if (SpringUtils.applicationContext == null) {
SpringUtils.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//根据name
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
//根据类型
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
在使用时调用SpringUtils.getBean(String name)或SpringUtils.getBean(Class<T> clazz)方法,转换相应类型即可