Interesting things
有2天沒有寫diary report了辑莫,因為這幾天都在火車上顛簸学歧。上個星期五晚上9點的火車從廣州到武漢,星期日在學懈鞫郑考試枝笨,然后晚上9點的火車又匆忙的趕回廣州。今天是8點30趕到的廣州揭蜒,很累横浑。今天老大給我布置了一個新的Task,實現(xiàn)FastDFS的集群和負載均衡屉更♂闳冢看來今天是要加班的,F(xiàn)astDFS對我來說是一個未知的領域瑰谜,Spring Security 和 Filter欺冀、Interceptor的demo還沒有寫出來。(目測又要delay)我的時間計劃表是每天6點30起床萨脑,晚上加班到10點(正常是6點)隐轩,笨鳥先飛。
What did you do today
- 可插拔性渤早,在軟件系統(tǒng)的設計中职车,可插拔是一個重要特性。它意味著給系統(tǒng)添加新功能的時候(或者將原來功能的實現(xiàn)替換成新的實現(xiàn)而保持接口不變)鹊杖,不改變系統(tǒng)已有的功能提鸟。
- CMD (Common Module Definition):公共模塊定義,對于模塊的依賴仅淑,CMD是延遲執(zhí)行称勋,推崇依賴就近。
- 今天安裝VMware Workstation涯竟,這個玩意大學上嵌入式的時候用過(設置ip和掩碼:ifconfig eth0 192.168.1.2 netmask 255.255.255.0就是這樣用赡鲜,設置的ip是一次性,重啟虛擬機后就失效庐船, 設置網(wǎng)關:route add default gw 192.168.1.1)银酬,可是在我自己的筆記本我一直用Virtural Box。用起來Vmware還真不習慣筐钟,首先遇到一個問題就是虛擬機ping不同主機(真尼瑪?shù)疤?揩瞪,所以記錄一下。
-
進入虛擬機設置篓冲,把網(wǎng)絡連接設置為橋接模式李破。
-
點“高級”按鈕宠哄,記錄我們的MAC地址00:0C:29:67:76:2F
如果/etc/sysconfig/network-scripts目錄沒有ifcfg-eth0文件,那么我們就創(chuàng)建ifcfg-eth0文件嗤攻,cd /etc/sysconfig/network-scripts, touch ifcfg-eth0
-
vi ifcfg-eth0 ,對這個文件進行編輯毛嫉。具體的編輯內容可以參考圖片。
-
vi /etc/resolv.conf 進入resolv.conf文件設置dns妇菱。
-
vim /etc/rc.d/rc.local承粤,配置ifup eth0,讓開始時重啟eth0闯团。
-
重啟網(wǎng)絡服務辛臊,service network restart
-
我們滿懷期待的輸入ping 192.168.12.61(這個是主機地址),然后結果啪啪啪打臉房交,根本就ping不通嘛浪讳。
-
冥思苦想一下,發(fā)現(xiàn)是本地防火墻開啟的問題涌萤,那么我們關掉防火墻再試一試淹遵。果然是防火墻的問題,草他媽负溪。
-
我們本地的防火墻肯定不能關閉透揣,那么有沒有一種策略,能實現(xiàn)虛擬機ping通主機同時又保證本地防火墻保持開啟狀態(tài)呢川抡?肯定是有的辐真,打開Windows防火墻,找到高級設置崖堤。
-
我們在入站規(guī)則中找到“文件和打印機共享(回顯請求 - ICMPv4-In)”侍咱,然后啟動該規(guī)則即可解決問題。
-
但是我們又發(fā)現(xiàn)一個問題密幔,我們ping不通www.baidu.com楔脯,這個問題就很操蛋了。
-
我們只需要把nameserver 設置為 114.114.114.114就能解決虛擬機ping不通外網(wǎng)的問題胯甩。
-
后續(xù)更新文章
如果你沒有插網(wǎng)線的話, ifconfig應該是沒有本地適配器的ip昧廷。反之你是wifi連接的話,ifconfig會出現(xiàn)網(wǎng)卡的ip和網(wǎng)關偎箫。我們在配置虛擬機使 ip和網(wǎng)卡的ip在同一網(wǎng)段木柬,網(wǎng)關應該和電腦網(wǎng)卡保持一致即可。
Vmware的三種模式配置,我之前這篇文章有講過你應該知道的VirtualBox虛擬機網(wǎng)絡配置
這里我再復述一遍(以前內容取自于網(wǎng)絡):
VMWare提供了三種工作模式淹办,它們是bridged(橋接模式)眉枕、NAT(網(wǎng)絡地址轉換模式)和host-only(主機模式)。要想在網(wǎng)絡管理和維護中合理應用它們,你就應該先了解一下這三種工作模式速挑。
-
Bridged(橋接模式)
- 在這種模式下谤牡,VMWare虛擬出來的操作系統(tǒng)就像是局域網(wǎng)中的一臺獨立的主機,它可以訪問網(wǎng)內任何一臺機器梗摇。在橋接模式下,你需要手工為虛擬系統(tǒng)配置IP地址想许、子網(wǎng)掩碼伶授,而且還要和宿主機器處于同一網(wǎng)段,這樣虛擬系統(tǒng)才能和宿主機器進行通信流纹。同時糜烹,由于這個虛擬系統(tǒng)是局域網(wǎng)中的一個獨立的主機系統(tǒng),那么就可以手工配置它的TCP/IP配置信息漱凝,以實現(xiàn)通過局域網(wǎng)的網(wǎng)關或路由器訪問互聯(lián)網(wǎng)疮蹦。
- 使用橋接模式的虛擬系統(tǒng)和宿主機器的關系,就像連接在同一個Hub上的兩臺電腦茸炒。想讓它們相互通訊愕乎,你就需要為虛擬系統(tǒng)配置IP地址和子網(wǎng)掩碼,否則就無法通信壁公。
- 如果你想利用VMWare在局域網(wǎng)內新建一個虛擬服務器感论,為局域網(wǎng)用戶提供網(wǎng)絡服務,就應該選擇橋接模式紊册。
-
host-only(主機模式)
- 在某些特殊的網(wǎng)絡調試環(huán)境中比肄,要求將真實環(huán)境和虛擬環(huán)境隔離開,這時你就可采用host-only模式囊陡。在host-only模式中芳绩,所有的虛擬系統(tǒng)是可以相互通信的,但虛擬系統(tǒng)和真實的網(wǎng)絡是被隔離開的撞反。
- 提示:在host-only模式下妥色,虛擬系統(tǒng)和宿主機器系統(tǒng)是可以相互通信的,相當于這兩臺機器通過雙絞線互連遏片。
- 在host-only模式下垛膝,虛擬系統(tǒng)的TCP/IP配置信息(如IP地址、網(wǎng)關地址丁稀、DNS服務器等)吼拥,都是由VMnet1(host-only)虛擬網(wǎng)絡的DHCP服務器來動態(tài)分配的。
- 如果你想利用VMWare創(chuàng)建一個與網(wǎng)內其他機器相隔離的虛擬系統(tǒng)线衫,進行某些特殊的網(wǎng)絡調試工作凿可,可以選擇host-only模式。
-
NAT(網(wǎng)絡地址轉換模式)
- 使用NAT模式,就是讓虛擬系統(tǒng)借助NAT(網(wǎng)絡地址轉換)功能枯跑,通過宿主機器所在的網(wǎng)絡來訪問公網(wǎng)惨驶。也就是說,使用NAT模式可以實現(xiàn)在虛擬系統(tǒng)里訪問互聯(lián)網(wǎng)敛助。NAT模式下的虛擬系統(tǒng)的TCP/IP配置信息是由VMnet8(NAT)虛擬網(wǎng)絡的DHCP服務器提供的粗卜,無法進行手工修改,因此虛擬系統(tǒng)也就無法和本局域網(wǎng)中的其他真實主機進行通訊纳击。采用NAT模式最大的優(yōu)勢是虛擬系統(tǒng)接入互聯(lián)網(wǎng)非常簡單续扔,你不需要進行任何其他的配置,只需要宿主機器能訪問互聯(lián)網(wǎng)即可焕数。
- 如果你想利用VMWare安裝一個新的虛擬系統(tǒng)纱昧,在虛擬系統(tǒng)中不用進行任何手工配置就能直接訪問互聯(lián)網(wǎng),建議你采用NAT模式堡赔。
提示:以上所提到的NAT模式下的VMnet8虛擬網(wǎng)絡识脆,host-only模式下的VMnet1虛擬網(wǎng)絡,以及bridged模式下的VMnet0虛擬網(wǎng)絡善已,都是由VMWare虛擬機自動配置而生成的灼捂,不需要用戶自行設置。VMnet8和VMnet1提供DHCP服務换团,VMnet0虛擬網(wǎng)絡則不提供纵东。
言歸正傳, 如果你的虛擬機出現(xiàn)了ping不通百度的情況。一個原因是DNS,另一個原因就是沒有配置VMware Virtual Ethernet Adapter for VMnet8 的ip和網(wǎng)關地址啥寇。 這里的ip同樣要和電腦網(wǎng)卡的ip處于同一網(wǎng)段, 網(wǎng)關地址和電腦網(wǎng)卡一樣即可偎球。
這里在衍生一個問題。 同一個物理地址下內的不同邏輯網(wǎng)段能否通信 ?
小馬 :其實是不能的辑甜。這里要扯出子網(wǎng)掩碼的概念衰絮,子網(wǎng)掩碼不能單獨存在,它必須結合IP地址一起使用磷醋。子網(wǎng)掩碼只有一個作用猫牡,就是將某個IP地址劃分成網(wǎng)絡地址和主機地址。
小馬: 例如兩臺電腦分別是192.168.0.1/24和192.168.0.135/25邓线,用192.168.0.1去ping 192.168.0.135淌友,因為192.168.0.1/24中包含192.168.0.135,數(shù)據(jù)包可以發(fā)送到骇陈,但是192.168.0.135這臺電腦僅能訪問192.168.0.129-254震庭,所以返回的數(shù)據(jù)不能直接傳給192.168.0.1,而是要把數(shù)據(jù)發(fā)給網(wǎng)關進行轉發(fā)你雌,如果沒有網(wǎng)關器联,則會將數(shù)據(jù)包丟棄二汛。
小馬: 192.168.0.1/24,說明前24位是網(wǎng)絡地址, 后8位是主機地址。如果要算廣播IP的話拨拓,就是主機地址都為1肴颊。因此我們可以算出其子網(wǎng)掩碼是255.255.255.0。子網(wǎng)掩碼按位與IP地址可以算出網(wǎng)絡地址是192.168.0.0, 廣播地址是192.168.0.255渣磷。子網(wǎng)掩碼的長度也是32位婿着,左邊是網(wǎng)絡位,用二進制數(shù)字“1”表示醋界,1的數(shù)目等于網(wǎng)絡位的長度竟宋;右邊是主機位,用二進制數(shù)字“0”表示物独,0的數(shù)目等于主機位的長度袜硫。這樣做的目的是為了讓掩碼與ip地址做按位與運算時用0遮住原主機數(shù)氯葬,而不改變原網(wǎng)絡段數(shù)字挡篓,而且很容易通過0的位數(shù)確定子網(wǎng)的主機數(shù)(2的主機位數(shù)次方-2,因為主機號全為1時表示該網(wǎng)絡廣播地址帚称,全為0時表示該網(wǎng)絡的網(wǎng)絡號官研,這是兩個特殊地址)。所以我們可以算出子網(wǎng)的ip數(shù)是2的8次方 - 2 = 254(第一個地址是網(wǎng)絡地址和最后一個地址是廣播地址, 需要去掉)闯睹。那么其子網(wǎng)ip的范圍就是192.168.0.1 - 192.168.0.254
小馬: 同理可得192.168.0.135/25的子網(wǎng)掩碼是255.255.255.128戏羽,網(wǎng)絡地址是192.168.0.128,廣播地址是192.168.0.255,子網(wǎng)ip范圍是192.168.0.129-192.168.0.254楼吃。子網(wǎng)ip數(shù)量=2的7次方-2 = 126始花。所以解答了同一物理地址下內的不同邏輯網(wǎng)段是不能通信的。
小馬: 擴展知識, 網(wǎng)絡地址=IP地址&子網(wǎng)掩碼, 主機地址=IP地址&按位非(子網(wǎng)掩碼)孩锡,廣播地址=主機位都是1酷宵。A類地址開頭是0, 0-127。B類地址開頭是10, 128-191,
C類地址開頭是110, 192-223躬窜。
- 關于<mvc:annotation-driven />這個問題浇垦,我們接著上一篇博客講,我上一篇博客的觀點出自于使用@Controller注解為什么要配置<mvc:annotation-driven />荣挨,這篇博客作者的觀點是"要使用spring mvc中的@Controller注解男韧,就必須要配置<mvc:annotation-driven />,否則org.springframework.web.servlet.DispatcherServlet無法找到控制器并把請求分發(fā)到控制器默垄。" 當我剛開始學習SpringMVC的時候此虑,就看過這篇文章,這篇文章某些觀點的確解決了我的一些開發(fā)問題口锭,但是我上面列舉的作者觀點就錯的有點離譜寡壮。 下面我就用代碼去證明這個觀點是錯的!
-
我們在spring-servlet注釋<mvc:annotation-driven />這一行代碼。
- 定義一個MvcAnnotationDrivenTestController
-
@RequestMapping("/mvc")
@Controller
public class MvcAnnotationDrivenTestController {
@RequestMapping(value = "/testMvcAnnotationDriven", method = RequestMethod.GET)
public ModelAndView testMvcAnnotationDriven() {
return new ModelAndView("mvc_annotation_driven_test");
}
}
- 在/WEB-INF/jsp/下面况既,定義mvc_annotation_driven_test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>mvc_annotation_driven_test</title>
</head>
<body>
hello, this is mvc_annotation_driven_test
</body>
</html>
- 我們啟動tomcat这溅,輸入http://localhost:8080/mvc/testMvcAnnotationDriven,我們就證明了"使用spring mvc中的@Controller注解棒仍,就必須要配置<mvc:annotation-driven />" 這個觀點是錯的了悲靴。
- 接下來我們在定義一個TestController,我們可以提供一個問題:“如果不在spring-servlet文件中配置<mvc:annotation-driven />莫其,我們能成功的去訪問http://localhost:8080/test/interceptor1這個鏈接嗎癞尚?” 答案是不能訪問!B叶浮浇揩!
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/interceptor1")
public String testInterceptor1(HttpSession session) {
session.setAttribute("test1", "interceptor1");
session.invalidate();
return "testInterceptor1";
}
@GetMapping("/interceptor2")
public String testInterceptor2(HttpSession session) {
session.setAttribute("test2", "interceptor2");
session.invalidate();
return "testInterceptor2";
}
}
* 會拋出"[20:02:37:859] [WARN] - org.springframework.web.servlet.DispatcherServlet.noHandlerFound(DispatcherServlet.java:1176) - No mapping found for HTTP request with URI [/test/interceptor1] in DispatcherServlet with name 'filter_interceptor_mvc'"這個錯誤,造成404憨颠。
- 我們可以去官方的一些文檔找到答案胳徽。<mvc:annotation-driven/>其實是毫無意義的。它聲明了對注解驅動(@RequestMapping, @Controller)的mvc控制器的顯式支持爽彤,盡管對這些的支持是默認行為养盗。
<mvc:annotation-driven /> is actually rather pointless. It declares explicit support for annotation-driven MVC controllers (i.e.@RequestMapping, @Controller, etc), even though support for those is the default behaviour.
- 翻譯后的意思就是:我的建議總是聲明<context:annotation-config/>,但是不要打擾<mvc:annotation-driven/>适篙,除非你想通過Jackson來支持Json往核。
My advice is to always declare <context:annotation-config>, but don't bother with <mvc:annotation-driven /> unless you want JSON support via Jackson.
我想上面的解釋能解開你們心中的疑惑。美滋滋!
-
接下來的篇幅會講Listener嚷节、Filter聂儒、Interceptor的demo(終于可以還債了)。
- 創(chuàng)建TestInterceptor1硫痰、TestInterceptor2衩婚。
@Slf4j
public class TestInterceptor1 extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("TestInteceptor1 preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("TestInterceptor1 postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("TestInterceptor1 afterCompletion");
}
}
@Slf4j
public class TestInterceptor2 extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("TestInterceptor2 preHandle");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("TestInterceptor2 postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("TestInterceptor2 afterCompletion");
}
}
- 創(chuàng)建TestFilter1、TestFilter2碍论。
@Slf4j
public class TestFilter1 extends OncePerRequestFilter {
private String username;
private String password;
public TestFilter1() {}
public TestFilter1(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
log.info("TestFilter1 doFilterInternal started, username = {} , password = {} ", username, password);
filterChain.doFilter(httpServletRequest, httpServletResponse);
log.info("TestFilter1 doFilterInternal end, username = {} , password = {}", username, password);
}
}
@Slf4j
public class TestFilter2 extends OncePerRequestFilter {
private String username;
private String password;
public TestFilter2() {}
public TestFilter2(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
log.info("TestFilter2 doFilterInternal started");
filterChain.doFilter(httpServletRequest, httpServletResponse);
log.info("TestFilter2 doFilterInternal end");
}
}
- 創(chuàng)建ContextListener谅猾、RequestListener、RequestAttributeListener鳍悠、SessionListener税娜。
@Slf4j
public class ContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
log.info("context initialized");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
log.info("context destroyed");
}
}
@Slf4j
public class RequesListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
log.info("request destroyed");
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
log.info("request initialized");
}
}
@Slf4j
public class RequestAttributeListener implements ServletRequestAttributeListener {
@Override
public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
log.info("attribute added");
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
log.info("attribute removed");
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
log.info("attribute replaced");
}
}
@Slf4j
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
log.info("session created");
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
log.info("session destroyed");
}
}
- 在web.xml配置Filter、Listener
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>filter_interceptor</display-name>
<welcome-file-list>
<welcome-file>cmazxiaoma.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-config.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextCleanupListener</listener-class>
</listener>
<listener>
<listener-class>com.cmazxiaoma.demo.listener.ContextListener</listener-class>
</listener>
<listener>
<listener-class>com.cmazxiaoma.demo.listener.RequesListener</listener-class>
</listener>
<listener>
<listener-class>com.cmazxiaoma.demo.listener.RequestAttributeListener</listener-class>
</listener>
<listener>
<listener-class>com.cmazxiaoma.demo.listener.SessionListener</listener-class>
</listener>
<servlet>
<servlet-name>filter_interceptor_mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<init-param>
<param-name>detectAllHandlerExceptionResolvers</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>filter_interceptor_mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>testFilter1</filter-name>
<filter-class>com.cmazxiaoma.demo.filter.TestFilter1</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>username</param-name>
<param-value>testFilter1</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>testFilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>testFilter2</filter-name>
<filter-class>com.cmazxiaoma.demo.filter.TestFilter2</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>username</param-name>
<param-value>testFilter2</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>456</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>testFilter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- 在servlet-servlet中配置Interceptor藏研。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/test/interceptor1"/>
<bean class="com.cmazxiaoma.demo.interceptor.TestInterceptor1" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/test/interceptor2"/>
<bean class="com.cmazxiaoma.demo.interceptor.TestInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
- 我們輸入http://localhost:8080/test/interceptor1敬矩,觀看控制臺打出的log和返回的視圖。
[21:19:03:666] [INFO] - com.cmazxiaoma.demo.listener.RequesListener.requestInitialized(RequesListener.java:18) - request initialized
[21:19:03:666] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:666] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:667] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:667] [INFO] - com.cmazxiaoma.demo.filter.TestFilter1.doFilterInternal(TestFilter1.java:44) - TestFilter1 doFilterInternal started, username = testFilter1 , password = 123
[21:19:03:667] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:667] [INFO] - com.cmazxiaoma.demo.filter.TestFilter2.doFilterInternal(TestFilter2.java:42) - TestFilter2 doFilterInternal started
[21:19:03:680] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:680] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:680] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:681] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:681] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:681] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:685] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:686] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:686] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:691] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:03:691] [INFO] - com.cmazxiaoma.demo.interceptor.TestInterceptor1.preHandle(TestInterceptor1.java:15) - TestInteceptor1 preHandle
[21:19:03:705] [INFO] - com.cmazxiaoma.demo.listener.SessionListener.sessionDestroyed(SessionListener.java:18) - session destroyed
[21:19:03:718] [INFO] - com.cmazxiaoma.demo.interceptor.TestInterceptor1.postHandle(TestInterceptor1.java:22) - TestInterceptor1 postHandle
[21:19:03:718] [INFO] - com.cmazxiaoma.demo.interceptor.TestInterceptor1.afterCompletion(TestInterceptor1.java:27) - TestInterceptor1 afterCompletion
[21:19:03:719] [INFO] - com.cmazxiaoma.demo.filter.TestFilter2.doFilterInternal(TestFilter2.java:44) - TestFilter2 doFilterInternal end
[21:19:03:719] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeRemoved(RequestAttributeListener.java:18) - attribute removed
[21:19:03:719] [INFO] - com.cmazxiaoma.demo.filter.TestFilter1.doFilterInternal(TestFilter1.java:46) - TestFilter1 doFilterInternal end, username = testFilter1 , password = 123
[21:19:03:719] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeRemoved(RequestAttributeListener.java:18) - attribute removed
[21:19:03:719] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeRemoved(RequestAttributeListener.java:18) - attribute removed
[21:19:03:719] [INFO] - com.cmazxiaoma.demo.listener.RequesListener.requestDestroyed(RequesListener.java:13) - request destroyed
- 我們輸入http://localhost:8080/test/interceptor2蠢挡,控制臺打出的log和返回的視圖弧岳。
[21:19:46:054] [INFO] - com.cmazxiaoma.demo.listener.RequesListener.requestInitialized(RequesListener.java:18) - request initialized
[21:19:46:055] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:056] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:056] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:056] [INFO] - com.cmazxiaoma.demo.filter.TestFilter1.doFilterInternal(TestFilter1.java:44) - TestFilter1 doFilterInternal started, username = testFilter1 , password = 123
[21:19:46:056] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:057] [INFO] - com.cmazxiaoma.demo.filter.TestFilter2.doFilterInternal(TestFilter2.java:42) - TestFilter2 doFilterInternal started
[21:19:46:057] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:057] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:058] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:058] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:059] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:059] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:059] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:060] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:060] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:061] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeAdded(RequestAttributeListener.java:13) - attribute added
[21:19:46:061] [INFO] - com.cmazxiaoma.demo.interceptor.TestInterceptor2.preHandle(TestInterceptor2.java:15) - TestInterceptor2 preHandle
[21:19:46:061] [INFO] - com.cmazxiaoma.demo.filter.TestFilter2.doFilterInternal(TestFilter2.java:44) - TestFilter2 doFilterInternal end
[21:19:46:062] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeRemoved(RequestAttributeListener.java:18) - attribute removed
[21:19:46:062] [INFO] - com.cmazxiaoma.demo.filter.TestFilter1.doFilterInternal(TestFilter1.java:46) - TestFilter1 doFilterInternal end, username = testFilter1 , password = 123
[21:19:46:062] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeRemoved(RequestAttributeListener.java:18) - attribute removed
[21:19:46:062] [INFO] - com.cmazxiaoma.demo.listener.RequestAttributeListener.attributeRemoved(RequestAttributeListener.java:18) - attribute removed
[21:19:46:063] [INFO] - com.cmazxiaoma.demo.listener.RequesListener.requestDestroyed(RequesListener.java:13) - request destroyed
通過對比log和返回的視圖凳忙,我們發(fā)現(xiàn)了Interceptor1執(zhí)行了preHandler()、postHandler()禽炬、afterCompletion()這三個方法涧卵,而Interceptor2只執(zhí)行了preHandler()這個方法。通過比較它們的源碼腹尖,我們發(fā)現(xiàn)了Interceptor1的preHandler()返回的是true柳恐,而Interceptor2的preHandler()返回的是false。而第一個url我們攔截了請求热幔,返回了視圖乐设,第二個url我們攔截了請求,返回沒有視圖绎巨。
preHandle方法是進行處理攔截用的近尚,該方法將在Controller處理之前調用,Interceptor攔截器是鏈式的场勤,并且可以中斷戈锻,當返回false的時候整個請求結束。
當preHandle返回true時却嗡,postHandle()才會執(zhí)行舶沛,在Controller的方法調用之后執(zhí)行嘹承,但是它會在DispatcherServlet進行視圖的渲染之前執(zhí)行窗价。
當preHandle返回ture才會執(zhí)行,該方法將在整個請求完成之后叹卷,也就是DispatcherServlet渲染視完畢才執(zhí)行撼港,主要作用是情理資源。
從啟動日志來看骤竹,Listener > Filter > Interceptor > Servlet帝牡,自定義Listener和Filter很簡單,也不需要講蒙揣。
What to do tomorrow
- 明天去看FastDFS的集群和負載均衡靶溜,Spring Security的demo又要delay了。
Summary
笨鳥先飛