Filter和Listener
1. Filter
- 概念:Filter(過濾器),當(dāng)訪問服務(wù)器資源時(shí),過濾器可以將請(qǐng)求攔截下來完成一系列特殊的功能。
- 作用:Filter一般用于完成通用的操作,如:登錄驗(yàn)證,統(tǒng)一編碼處理,敏感字符的過濾。
- 使用步驟:
- 定義一個(gè)類并實(shí)現(xiàn)接口Filter
- 復(fù)寫Filter接口中的方法
- 配置攔截路徑:
- web.xml配置攔截路徑
<!-- 在web.xml中 --> <!-- 過濾器配置 --> <filter> <!-- 配置過濾器的名稱 --> <filter-name>demo</filter-name> <!-- 配置過濾器的全類名 --> <filter-class>com.hsh.study.web.filter.FilterDemo</filter-class> </filter> <!-- 配置過濾器映射 --> <filter-mapping> <!-- 對(duì)應(yīng)過濾器的名稱 --> <filter-name>demo</filter-name> <!-- 配置攔截路徑 --> <url-pattern>/*</url-pattern> </filter-mapping> - 通過注解的方式配置攔截路徑
// 訪問所有資源之前,都會(huì)執(zhí)行該過濾器 @WebFilter("/*") // 定義的類實(shí)現(xiàn)Filter public class FilterDemo1 implements Filter { // 過濾器初始化方法 @Override public void init(FilterConfig filterConfig) throws ServletException { } // 主要方法 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 訪問資源文件之前會(huì)先執(zhí)行此重寫方法,只有資源放行后才能訪問 System.out.println("filterDemo1被執(zhí)行了...."); // 放行 filterChain.doFilter(servletRequest,servletResponse); } // 過濾器銷毀方法 @Override public void destroy() { } }
- web.xml配置攔截路徑
- 過濾器的執(zhí)行執(zhí)行過程:
- 執(zhí)行過濾器
- 執(zhí)行放行后的資源
- 回來執(zhí)行過濾器放行代碼后的代碼
- 過濾器的生命周期:
- init:在服務(wù)器啟動(dòng)后,創(chuàng)建Filter對(duì)象然后調(diào)用init方法。只執(zhí)行一次,通常用于加載資源。
- doFilter:在每一次請(qǐng)求被攔截資源時(shí)執(zhí)行,執(zhí)行多次。
- destory:在服務(wù)器關(guān)閉后,F(xiàn)ilter對(duì)象被銷毀。如果服務(wù)器時(shí)正常關(guān)閉,則執(zhí)行destory方法。只執(zhí)行一次,通常用于釋放資源
- 過濾器的配置:
- 攔截路徑配置
- 具體的資源路徑: /index.jsp 只有訪問index.jsp時(shí),過濾器才會(huì)被執(zhí)行。
- 攔截目錄: /user/* 訪問/user下的資源時(shí),過濾器都會(huì)被執(zhí)行。
- 后綴名攔截: *.jsp 訪問所有后綴名為.jsp的文件時(shí),過濾器都會(huì)被執(zhí)行。
- 攔截所有資源: /* 訪問所有資源時(shí),過濾器都會(huì)被執(zhí)行。
- 攔截方式配置:資源被訪問的方式
- 注解配置
- 設(shè)置dispatcherTypes屬性:
- REQUEST:默認(rèn)值,瀏覽器直接請(qǐng)求資源
- FORWARD:轉(zhuǎn)發(fā)訪問資源
- INCLUDE:包含訪問資源
- ERROR:錯(cuò)誤跳轉(zhuǎn)資源
- ASYNC:異步訪問資源
- 設(shè)置dispatcherTypes屬性:
- web.xml配置
- 設(shè)置<dispatcher></dispatcher>標(biāo)簽即可
- 注解配置
- 攔截路徑配置
- 過濾器鏈(配置多個(gè)過濾器時(shí))
- 執(zhí)行順序:假設(shè)有兩個(gè)過濾器<過濾器1,過濾器2>
graph LR A[過濾器1]-->B[過濾器2] B[過濾器2]-->C[放行后資源執(zhí)行] C[放行后資源執(zhí)行]-->D[過濾器2] D[過濾器2]-->E[過濾器1] - 過濾器執(zhí)行順序:
- 注解配置
- 按照類名的字符串比較規(guī)則比較,值小的先執(zhí)行。如
AFilter和BFilter,先執(zhí)行AFilter
- 按照類名的字符串比較規(guī)則比較,值小的先執(zhí)行。如
- web.xml配置
- 誰的<filter-mapping></filter-mapping>定義在上邊,誰先執(zhí)行。
- 注解配置
- 執(zhí)行順序:假設(shè)有兩個(gè)過濾器<過濾器1,過濾器2>
代理模式
- 概念:
- 真實(shí)對(duì)象:被代理的對(duì)象
- 代理對(duì)象:代理真實(shí)的對(duì)象
- 代理模式:代理對(duì)象代理真實(shí)對(duì)象,達(dá)到增強(qiáng)真實(shí)對(duì)象功能的目的
- 實(shí)現(xiàn)方法:
- 靜態(tài)代理:有一個(gè)類文件描述代理模式
- 動(dòng)態(tài)代理:在內(nèi)存中形成代理類
- 實(shí)現(xiàn)步驟:
- 代理對(duì)象和真實(shí)對(duì)象實(shí)現(xiàn)相同的接口
- 代理對(duì)象 = Proxy.newProxyInstance();
- 使用代理對(duì)象調(diào)用方法
- 增強(qiáng)原有對(duì)象的方法
- 增強(qiáng)方式:
- 增強(qiáng)參數(shù)列表
- 增強(qiáng)返回值類型
- 增強(qiáng)方法體執(zhí)行邏輯
- 具體的實(shí)現(xiàn)
// 接口類 public interface SaleComputer { public String sale(double money); public void show(); } // 實(shí)現(xiàn)接口的實(shí)體類 public class Lenovo implements SaleComputer { @Override public String sale(double money) { System.out.println("花了"+money+"元買了一臺(tái)聯(lián)想電腦..."); return "聯(lián)想電腦"; } @Override public void show() { System.out.println("展示電腦...."); } } //動(dòng)態(tài)代理實(shí)現(xiàn)類 public class ProxyTest { public static void main(String[] args) { //1.創(chuàng)建真實(shí)對(duì)象 Lenovo lenovo = new Lenovo(); //2.動(dòng)態(tài)代理增強(qiáng)lenovo對(duì)象 /* 三個(gè)參數(shù): 1. 類加載器:真實(shí)對(duì)象.getClass().getClassLoader() 2. 接口數(shù)組:真實(shí)對(duì)象.getClass().getInterfaces() 3. 處理器:new InvocationHandler() */ SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() { /* 代理邏輯編寫的方法:代理對(duì)象調(diào)用的所有方法都會(huì)觸發(fā)該方法執(zhí)行 參數(shù): 1. proxy:代理對(duì)象 2. method:代理對(duì)象調(diào)用的方法,被封裝為的對(duì)象 3. args:代理對(duì)象調(diào)用的方法時(shí),傳遞的實(shí)際參數(shù) */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /*System.out.println("該方法執(zhí)行了...."); System.out.println(method.getName()); System.out.println(args[0]); */ //判斷是否是sale方法 if(method.getName().equals("sale")){ //1.增強(qiáng)參數(shù) double money = (double) args[0]; money = money * 0.85; System.out.println("專車接你...."); //使用真實(shí)對(duì)象調(diào)用該方法 String obj = (String) method.invoke(lenovo, money); System.out.println("免費(fèi)送貨..."); //2.增強(qiáng)返回值 return obj+"_鼠標(biāo)墊"; }else{ Object obj = method.invoke(lenovo, args); return obj; } } }); //3.調(diào)用方法 String computer = proxy_lenovo.sale(8000); System.out.println(computer); proxy_lenovo.show(); } }
2. Listener
- 概念:
- 事件監(jiān)聽機(jī)制:
- 事件:一件事情
- 事件源:事件發(fā)生的地方
- 監(jiān)聽器:一個(gè)對(duì)象
- 注冊(cè)監(jiān)聽:將事件、事件源、監(jiān)聽器綁定在一起。當(dāng)事件源上發(fā)生指定事件時(shí),執(zhí)行監(jiān)聽器處理事件。
- 事件監(jiān)聽機(jī)制:
- 按監(jiān)聽的對(duì)象Servlet監(jiān)聽器可以分為如下幾類:
- 監(jiān)聽?wèi)?yīng)用程序環(huán)境(ServletContext)
- 監(jiān)聽繪畫對(duì)象(HttpSession)
- 監(jiān)聽請(qǐng)求消息對(duì)象(ServletRequest)
- 監(jiān)聽器常用接口
- ServletContextListener接口
- 用于監(jiān)聽代表Web應(yīng)用程序的ServletContext對(duì)象創(chuàng)建和銷毀的事件
- HttpSessionListener接口
- 用于監(jiān)聽Web應(yīng)用程序中的用戶會(huì)話HttpSession對(duì)象的創(chuàng)建和銷毀的事件
- HttpSessionListener接口可以在session創(chuàng)建后或session無效前得到通知,接口中的方法為:
- sessionCreated():session創(chuàng)建時(shí)調(diào)用此方法
- sessionDestoryed():session銷毀前調(diào)用該方法
- ServletRequestListener接口
- 用于監(jiān)聽Web應(yīng)用程序中的ServletRequest對(duì)象的創(chuàng)建和銷毀的事件
- ServletContextListener接口
- ServletContextListener:監(jiān)聽ServletContext對(duì)象的創(chuàng)建和銷毀
- 方法:
- void contextDestoryed(ServletContextEvent sce) : ServletContext對(duì)象被銷毀之前會(huì)調(diào)用該方法
- void contextInitialized(ServletContextEvent sce) : ServletContext對(duì)象創(chuàng)建后會(huì)調(diào)用該方法
- 步驟:
- 定義一個(gè)類,實(shí)現(xiàn)ServletContextListener接口
- 復(fù)寫方法
- 配置
- web.xml的配置
<listener> <!-- 監(jiān)聽器所在的全類名 --> <listener-class>com.hsh.study.ContextLoaderListener</listener-class> </listener> - 注解配置:
@WebListener
- web.xml的配置
- 方法: