①客戶端的全部請求都交給前端控制器DispatcherServlet來處理,它會負責調用系統的其餘模塊來真正處理用戶的請求。前端
② DispatcherServlet收到請求後,將根據請求的信息(包括URL、HTTP協議方法、請求頭、請求參數、Cookie等)以及HandlerMapping的配置找處處理該請求的Handler(任何一個對象均可以做爲請求的Handler)。java
③在這個地方Spring會經過HandlerAdapter對該處理器進行封裝。web
④ HandlerAdapter是一個適配器,它用統一的接口對各類Handler中的方法進行調用。spring
⑤ Handler完成對用戶請求的處理後,會返回一個ModelAndView對象給DispatcherServlet,ModelAndView顧名思義,包含了數據模型以及相應的視圖的信息。數據庫
⑥ ModelAndView的視圖是邏輯視圖,DispatcherServlet還要藉助ViewResolver完成從邏輯視圖到真實視圖對象的解析工做。 ⑦ 當獲得真正的視圖對象後,DispatcherServlet會利用視圖對象對模型數據進行渲染。瀏覽器
⑧ 客戶端獲得響應,多是一個普通的HTML頁面,也能夠是XML或JSON字符串,還能夠是一張圖片或者一個PDF文件。安全
一、用戶發送請求時會先從DispathcherServler的doService方法開始,在該方法中會將ApplicationContext、localeResolver、themeResolver等對象添加到request中,緊接着就是調用doDispatch方法。服務器
二、進入該方法後首先會檢查該請求是不是文件上傳的請求(校驗的規則是是不是post而且contenttType是否爲multipart/爲前綴)即調用的是checkMultipart方法;若是是的將request包裝成MultipartHttpServletRequest。mvc
三、而後調用getHandler方法來匹配每一個HandlerMapping對象,若是匹配成功會返回這個Handle的處理鏈HandlerExecutionChain對象,在獲取該對象的內部其實也獲取咱們自定定義的攔截器,並執行了其中的方法。app
四、執行攔截器的preHandle方法,若是返回false執行afterCompletion方法並理解返回
五、經過上述獲取到了HandlerExecutionChain對象,經過該對象的getHandler()方法得到一個object經過HandlerAdapter進行封裝獲得HandlerAdapter對象。
六、該對象調用handle方法來執行Controller中的方法,該對象若是返回一個ModelAndView給DispatcherServlet。
七、DispatcherServlet藉助ViewResolver完成邏輯試圖名到真實視圖對象的解析,獲得View後DispatcherServlet使用這個View對ModelAndView中的模型數據進行視圖渲染。
Java Servlet 是運行在 Web 服務器或應用服務器上的程序,它是做爲來自 Web 瀏覽器或其餘 HTTP 客戶端的請求和 HTTP 服務器上的數據庫或應用程序之間的中間層。
使用 Servlet,您能夠收集來自網頁表單的用戶輸入,呈現來自數據庫或者其餘源的記錄,還能夠動態建立網頁。
Java Servlet 一般狀況下與使用 CGI(Common Gateway Interface,公共網關接口)實現的程序能夠達到殊途同歸的效果。可是相比於 CGI,Servlet 有如下幾點優點:
性能明顯更好。
Servlet 在 Web 服務器的地址空間內執行。這樣它就沒有必要再建立一個單獨的進程來處理每一個客戶端請求。
Servlet 是獨立於平臺的,由於它們是用 Java 編寫的。
服務器上的 Java 安全管理器執行了一系列限制,以保護服務器計算機上的資源。所以,Servlet 是可信的。
Java 類庫的所有功能對 Servlet 來講都是可用的。它能夠經過 sockets 和 RMI 機制與 applets、數據庫或其餘軟件進行交互。
SpringMVC是基於servlet,控制器基於方法級別的攔截,處理器設計爲單實例,因此應該瞭解一下Servlet的生命週期。
Servlet 加載—>實例化—>服務—>銷燬。
init():
在Servlet的生命週期中,僅執行一次init()方法。它是在服務器裝入Servlet時執行的,負責初始化Servlet對象。能夠配置服務器,以在啓動服務器或客戶機首次訪問Servlet時裝入Servlet。不管有多少客戶機訪問Servlet,都不會重複執行init()。
service():
它是Servlet的核心,負責響應客戶的請求。每當一個客戶請求一個HttpServlet對象,該對象的Service()方法就要調用,並且傳遞給這個方法一個「請求」(ServletRequest)對象和一個「響應」(ServletResponse)對象做爲參數。在HttpServlet中已存在Service()方法。默認的服務功能是調用與HTTP請求的方法相應的do功能。
destroy():
僅執行一次,在服務器端中止且卸載Servlet時執行該方法。當Servlet對象退出生命週期時,負責釋放佔用的資源。一個Servlet在運行service()方法時可能會產生其餘的線程,所以須要確認在調用destroy()方法時,這些線程已經終止或完成。
爲了讀取web.xml中的配置,咱們用到ServletConfig這個類,它表明當前Servlet在web.xml中的配置信息。經過web.xml中加載咱們本身寫的MyDispatcherServlet和讀取配置文件。
在前面咱們提到DispatcherServlet的initStrategies方法會初始化9大組件,可是這裏將實現一些SpringMVC的最基本的組件而不是所有,按順序包括:
每一次請求將會調用doGet或doPost方法,因此統一運行階段都放在doDispatch方法裏處理,它會根據url請求去HandlerMapping中匹配到對應的Method,而後利用反射機制調用Controller中的url對應的方法,並獲得結果返回。按順序包括如下功能:
/** * * 1.自定義DispatcherServlet<br> * 2.servlet init()方法初始化###只會執行一次<br> * ######2.1獲取當前包下全部的類<br> * ######2.2初始化當前包下全部的類,使用Java反射機制初始化對象存放在SpringMVC容器中key(beanId)- * value( 當前實例對象) <br> * ######2.3初始化HandlerMapping方法,將url和方法對應上 <br> * ########2.3.1使用Java反射技術讀取類的信息,存放在map集合中key爲url請求地址,value爲對應方法 * <br> * ########2.3.2使用Java反射技術讀取類的信息,存放在map集合中key爲url請求地址,value爲對應實例對象 * <br> * 3.servlet get或者post請求<br> * ######## 3.1.1獲取請求地址,使用Java反射技術找到對應的方法和實例對象進行執行 <br> */
public class ExtDispatcherServlet extends HttpServlet {
// mvc bean key=beanid ,value=對象
private ConcurrentHashMap<String, Object> mvcBeans = new ConcurrentHashMap<String, Object>();
// mvc 請求方法 key=requestUrl,value=對象
private ConcurrentHashMap<String, Object> mvcBeanUrl = new ConcurrentHashMap<String, Object>();
// mvc 請求方法 key=requestUrl,value=方法
private ConcurrentHashMap<String, String> mvcMethodUrl = new ConcurrentHashMap<String, String>();
/** * 初始化自定義SpringMVC容器 */
public void init() throws ServletException {
try {
// 1.獲取當前包下全部的類
List<Class<?>> classes = ClassUtil.getClasses("com.itmayiedu.ext.controller");
// 2.初始化當前包下全部的類,使用Java反射機制初始化對象存放在SpringMVC容器中key(beanId)-value(
// 當前實例對象)
findClassMVCBeans(classes);
// 3.初始化HandlerMapping方法,將url和方法對應上
handlerMapping(mvcBeans);
} catch (Exception e) {
}
}
// 2.初始化當前包下全部的類,使用Java反射機制初始化對象存放在SpringMVC容器中key(beanId)-value(
// 當前實例對象)
public void findClassMVCBeans(List<Class<?>> classes) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
mvcBeans = new ConcurrentHashMap<String, Object>();
for (Class<?> classInfo : classes) {
ExtController extController = classInfo.getDeclaredAnnotation(ExtController.class);
if (extController != null) {
// 默認類名小寫 做爲bean的名稱
String beanId = ClassUtil.toLowerCaseFirstOne(classInfo.getSimpleName());
mvcBeans.put(beanId, ClassUtil.newInstance(classInfo));
}
}
}
// 3.初始化HandlerMapping方法,將url和方法對應上
public void handlerMapping(ConcurrentHashMap<String, Object> mvcBeans) {
// 遍歷mvc bean對象
for (Map.Entry<String, Object> entry : mvcBeans.entrySet()) {
// springmvc 注入object對象
Object mvcObject = entry.getValue();
// 判斷類上是否有@ExtRequestMapping註解
Class<? extends Object> classInfo = mvcObject.getClass();
String requestBaseUrl = null;
ExtRequestMapping classExtRequestMapping = classInfo.getAnnotation(ExtRequestMapping.class);
if (classExtRequestMapping != null) {
requestBaseUrl = classExtRequestMapping.value();
}
// 遍歷當前類的全部方法,判斷方法上是否有註解
Method[] declaredMethods = classInfo.getDeclaredMethods();
for (Method method : declaredMethods) {
ExtRequestMapping methodExtRequestMapping = method.getDeclaredAnnotation(ExtRequestMapping.class);
if (methodExtRequestMapping != null) {
String httpRequestUrl = methodExtRequestMapping.value();
mvcBeanUrl.put(requestBaseUrl + httpRequestUrl, mvcObject);
mvcMethodUrl.put(requestBaseUrl + httpRequestUrl, method.getName());
}
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
doDispatch(req, resp);
} catch (Exception e) {
// TODO: handle exception
}
}
public void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// 1.獲取請求url地址
String requestUrl = req.getRequestURI();
// 2.使用請求url查找對應mvc 控制器bean
Object object = mvcBeanUrl.get(requestUrl);
if (object == null) {
resp.getWriter().println("http ext not found controller 404");
return;
}
// 3.獲取對應的請求方法
String methodName = mvcMethodUrl.get(requestUrl);
if (StringUtils.isEmpty(methodName)) {
resp.getWriter().println("http ext not found Method 404");
return;
}
// 4.使用java反射技術執行方法
Class<? extends Object> classInfo = object.getClass();
String resultPage = (String) methodInvoke(classInfo, object, methodName);
// 5.視圖展現
viewdisplay(resultPage, req, resp);
}
// 執行方法
public Object methodInvoke(Class<? extends Object> classInfo, Object object, String methodName) {
try {
Method method = classInfo.getMethod(methodName);
Object result = method.invoke(object);
return result;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 視圖展現
public void viewdisplay(String pageName, HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
// 獲取後綴信息
String suffix = ".jsp";
// 頁面目錄地址
String prefix = "/";
req.getRequestDispatcher(prefix + pageName + suffix).forward(req, res);
}
}
複製代碼
OnRefresh 是FrameworkServlet類中的提供的模塊方法,在其之類DispatchServlet中進行了重寫,
主要用於刷新Spring在web功能實現中所必須使用的全局變量。