小組的一次技術交流中提到手動實現一個mvc框架練練手,對於這個話題我很是的感興趣。因此寫着玩嘗試嘗試。web
說到mvc框架不得不得說當下最流行的spirngmvc了。下面就來分析下實現思路spring
首先,web項目確定都是基於servlet,咱們先來看看spirng是怎麼作的。mvc
隨便打開一個spirng的web項目啓動來看看app
這段日誌咱們能夠看出spring在剛啓動時正在初始化spirng的上下文。那麼初始化上下文又是在作什麼呢。咱們一步一步的來分析框架
首先spirng在ContextLoader中開始進行了初始化,那麼爲何ContextLoader會在應用啓動時初始化呢?this
緣由是在web.xml中有這樣一段配置url
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
點開裏面的源碼咱們能夠看到這個監聽器實現了ServletContextListener接口,實現了這個接口就能在應用啓動時自動執行contextInitialized方法,在這裏進行spring上下文的初始化spa
public void contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader(); if (this.contextLoader == null) { this.contextLoader = this; } this.contextLoader.initWebApplicationContext(event.getServletContext()); }
能夠在代碼中看到spring上下文初始化時傳入了servletContext。在剛開始學servlet時咱們知道servletContext是servlet的上下文,爲何要傳入這個下面再說日誌
讀取application.xml配置文件初始化WebApplicationContextxml
而後接着往下讀源碼發現WebApplicationContext保存在了servletContext,方便咱們隨時獲取WebApplicationContext,這就是爲何要在上圖方法中傳入servletContext。
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
初始化完WebApplicationContext接下來就是初始化springDispatcherServlet了。springDispatcherServlet是咱們springmvc的核心控制器,它其實就是個sevlet,配置在咱們的web.xml中
<servlet> <servlet-name>springDispatcherServlet</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> <load-on-startup>3</load-on-startup> </servlet>
springDispatcherServlet是咱們spirngmvc的整個核心控件。下面是一個請求的整個過程。具體再也不闡述
在接下來的日誌中咱們能夠看到來自AbstractUrlHandlerMapping的一堆咱們請求映射的打印。打開這個類看看它到底作了什麼。在registerHandler這個方法中咱們能夠看到
this.handlerMap.put(urlPath, resolvedHandler);
handlerMap是這個類中定義的一個map,而resolvedHandler則是這個請求的處理類對象。看到這裏思路就大概清晰了。springDispatcherServlet接到請求後,根據url找到對應的已經實例化好的處理對象,而後再執行相應的方法。
說到這裏大概的思路就已經有了。作個總結。
實現思路(只是個大概)
1.應用啓動初始化操做
建立一個contextLoader實現ServletContextListener接口
建立applicationContext上下文,存儲在servletContext中
讀取xml配置文件獲取掃描bean的包路徑
經過配置路徑獲取帶有註解的類
經過反射將類實例化,以類名首字母小寫或註解上的值爲key,實例化的對象爲value,將bean存儲在上下文中
2.初始化dispatchservlet
在web.xml中配置dispatchservlet,攔截全部請求
將全部類中的@requestMapping存儲在一個map中,key爲url,value爲class
將class(controller)反射實例化存儲在dispatchservlet的上下文中
從applicationContext獲取bean,爲filed注入實例
3.解析請求
dispatchservlet收到請求
經過threadLocal設置request和response方便在controller中使用。
根據url匹配到對應的class,根據class在dispatchservlet上下文中獲取實例。
根據註解value找到對應的方法執行,返回視圖。
本人道行尚淺,文中若有錯誤,歡迎指正。