在樂視風口浪尖的時候,勇於站出來講我是樂視的而不怕被打臉的,也就是我了。就算我之後不在樂視了,提起來在樂視工做過,我也仍是挺驕傲的。由於這是一個有理想,敢拼敢幹的公司。想起復仇者聯盟裏Fury指揮官的一句話:Until such time as the world ends, we will act as though it intends to spin on. 上週咱們去懷柔團建,人家都是兩個大人住一間,帶小孩子的是三我的一間。我帶着我家小王子兩人住了1380一晚的別墅,聽說是最好的房間。像我說過的,往往好事兒都讓我攤上了,因此仍是該幹啥幹啥。前端
咱們部門叫基礎業務平臺部,負責基本管理樂視視頻的視頻,音頻及所在的專輯數據。單臺QPS幾千,業內人士表示併發量不大,只是公司的集中緩存差強人意。web
開放平臺的系統框架是這樣的:redis
這是一個很規範的網站系統框架,基本能夠知足目前大部分SOA垂直拆分網站架構的需求。項目依賴關係是這樣的:spring
客戶層ope-web採用的是標準的spring mvc架構。定義了三個視圖解析器:編程
1>InternalResourceViewResolver 這個是UrlBasedViewResolver的方便子類。由於前端頁面採用的是JSP,這個必然是首選。後端
2>CommonsMultipartResolver 涉及上傳視頻和圖片,這個必不可少。須要注意最大上傳大小和最大佔用內存大小。緩存
3>SimpleMappingExceptionResolver 定義統一異常處理。咱們這個項目中配置的默認跳轉頁面defaultErrorView是404,異常時攜帶的屬性exceptionAttribute是ex。在exceptionMappings只定義了一個叫AccessException的異常,跳轉到errors頁面。安全
說到Spring MVC仍是先放一張架構圖吧架構
由圖中能夠看到整個spring mvc核心是dispatcherServlet,客戶端將請求提交給它,它查詢web.xml裏的mapping定義找到Controller。咱們項目mapping定義是併發
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
全部的請求都走這個dispatcherServlet,按照applicationContext.xml的配置處理,這裏面配置了自動掃描的controller路徑和上面提到的視圖解釋器。來看一眼dispatcherServlet的核心源碼:
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); //文件上傳解析,若是請求類型是multipart將經過MultipartResolver進行文件上傳解析; initLocaleResolver(context); //本地化解析 initThemeResolver(context); //主題解析 initHandlerMappings(context); //經過HandlerMapping,將請求映射處處理器 initHandlerAdapters(context); //經過HandlerAdapter支持多種類型的處理器 initHandlerExceptionResolvers(context); //若是執行過程當中遇到異常將交給HandlerExceptionResolver來解析 initRequestToViewNameTranslator(context); //直接解析請求到視圖名 initViewResolvers(context); //經過ViewResolver解析邏輯視圖名到具體視圖實現 initFlashMapManager(context); //flash映射管理器 }
從命名就能夠看出,這裏面主要用到了策略模式,對不一樣的視圖採用不一樣的策略。ApplicationContext是一個抽象接口,spring的上下文將框架內部的各個組件信息都經過一個context暴露給外部,是一個門面模式。
dispatcherServlet在進行請求分發的時候還提供了一些服務:
1>保存現場:保存request熟悉的快照,以便能在必要時恢復。
2>將框架須要的對象放入request中,以便view和handler使用。
3>在請求分發後恢復現場。
建議你們看看DispatcherServlet的源碼,常常作spring mvc項目的話,相信源碼不難看懂。你們可能常常遇到的問題,好比看了<Java併發編程實踐>這本書,感受這些東西項目中用不到啊。其實不是這樣,這本書很基礎,裏面的東西都用到了,只是封裝在框架裏了,不少人沒仔細研究而已。記得書裏講安全發佈的時候講到使用Collections.unmodifiableMap來發佈一個只讀的map。這個在DispatcherServlet源碼裏對它的運用很是的典型:將flashmap的一個快照保存在request的屬性裏以備查看用。
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); }
從源碼到原理,最基礎的,好比:調用構造器來建立一個Java類的時候,要知道這個構造器其實是一個靜態方法。因此第一次調用構造器建立對象的時候,或者訪問這個類的靜態方法或者靜態成員的時候,Java解釋器先要定位其字節碼(class)文件,加載了字段文件後,要進行全部的靜態初始化工做,這個工做只進行一次。
多想一想,從編碼到排查問題,相信都不會無從下手。
上面說了在spring裏能夠配置異常處理頁面,這個不經過spring直接走servlet也能夠,只要在web.xml裏配置一下:
DispatcherServlet還實現了一個很重要的功能:攔截器,咱們項目中主要用它來作用戶身份驗證。用戶身份驗證要走樂視網統一的SSO,在隔着我工位4,5排的用戶中心組那邊。只是一個外部接口的調用,可是總不能每次用戶發一個請求就調一次sso啊,外部調用network hops延時很嚴重的,因此這時候就用到了集中式緩存。取了一次以後將驗證身份的token存於redis裏,有效期24小時。
咱們組和SSO組中間隔着前端組。JSP的靜態頁和JS都是前端提供的。爲了進一步解耦先後端的工做,數據的加載都走的是js異步調用,數據由前端去渲染。爲了應對前端的修改,jSP中大量引入靜態分片。這個靜態分片由一個後臺服務定時將最新的分配刷新到本地。路徑保存在本地緩存中。本地緩存用的google的guava工具包。
再說攔截器,攔截器和servlet的過濾器很像,它們都是AOP變成思想的體現。這地方要注意:在web.xml配置的都是servlet的功能,在applicationContext裏配置的是spring mvc的功能。它們的區別也在這個地方。由於Filter是Servlet的規範,僅能在Servlet先後起做用。而interceptor和spring能夠親密互動,可以深刻到方法先後,異常拋出先後等,能夠訪問Action上下文,值棧裏的對象,可屢次被調用。
通常項目中用過濾器的就是utf8字符過濾器,在web.xml的配置以下:
<filter> <filter-name>CharacterEncodingFilter</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> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Servlet規範中還定義了一種特殊類,監聽器,用於監聽域對象的建立與銷燬,以及這些域對象屬性的修改事件。咱們項目中它來配置logback日誌的監聽。