目錄
監聽器配置流程(以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)方法,轉換相應類型即可