手写springmvc
手寫springmvc
既然已經(jīng)手寫了spring的IOC,那springmvc肯定也要嘗試寫寫了。手寫spring博客:https://www.cnblogs.com/xiaojiesir/p/11139203.html
SpringMVC的運(yùn)行流程:
?
(1)首先瀏覽器發(fā)送請(qǐng)求——>DispatcherServlet,前端控制器收到請(qǐng)求后自己不進(jìn)行處理,而是委托給其他的解析器進(jìn)行處理,作為統(tǒng)一訪問點(diǎn),進(jìn)行全局的流程控制;
(2)DispatcherServlet——>HandlerMapping,處理器映射器將會(huì)把請(qǐng)求映射為HandlerExecutionChain對(duì)象(包含一個(gè)Handler處理器對(duì)象、多個(gè)HandlerInterceptor攔截器)對(duì)象;
(3)DispatcherServlet——>HandlerAdapter,處理器適配器將會(huì)把處理器包裝為適配器,從而支持多種類型的處理器,即適配器設(shè)計(jì)模式的應(yīng)用,從而很容易支持很多類型的處理器;
(4)HandlerAdapter——>調(diào)用處理器相應(yīng)功能處理方法,并返回一個(gè)ModelAndView對(duì)象(包含模型數(shù)據(jù)、邏輯視圖名);
(5)ModelAndView對(duì)象(Model部分是業(yè)務(wù)對(duì)象返回的模型數(shù)據(jù),View部分為邏輯視圖名)——> ViewResolver, 視圖解析器將把邏輯視圖名解析為具體的View;
(6)View——>渲染,View會(huì)根據(jù)傳進(jìn)來的Model模型數(shù)據(jù)進(jìn)行渲染,此處的Model實(shí)際是一個(gè)Map數(shù)據(jù)結(jié)構(gòu);
(7)返回控制權(quán)給DispatcherServlet,由DispatcherServlet返回響應(yīng)給用戶,到此一個(gè)流程結(jié)束。
?
梳理SpringMVC的設(shè)計(jì)思路
在沒有使用框架前,我們是使用servlet來實(shí)現(xiàn)前后端交互的,所以springmvc說到底還是在servlet基礎(chǔ)上展開的。如果對(duì)servlet不是很熟悉的話,需要先學(xué)習(xí)下servlet。
框架只是方便開發(fā),底層知識(shí)才是最重要的。在掌握底層知識(shí)的基礎(chǔ)上,再學(xué)習(xí)框架的設(shè)計(jì)理念來成長自己。
Servlet?生命周期
Servlet 生命周期可被定義為從創(chuàng)建直到毀滅的整個(gè)過程。以下是 Servlet 遵循的過程:
- Servlet 通過調(diào)用?init ()?方法進(jìn)行初始化。
- Servlet 調(diào)用?service()?方法來處理客戶端的請(qǐng)求。
- Servlet 通過調(diào)用?destroy()?方法終止(結(jié)束)。
- 最后,Servlet 是由 JVM 的垃圾回收器進(jìn)行垃圾回收的。
?
根據(jù)servlet生命周期來看,我們可以在init()方法中初始化基本的beans,并實(shí)例化controller層中的定義的service的變量,同時(shí)實(shí)現(xiàn)映射URL請(qǐng)求的Path和方法。
而service方法我們用doget方法和dopost方法。doPost()主要是實(shí)現(xiàn)參數(shù)的解析,并通過反射的機(jī)制實(shí)現(xiàn)方法的調(diào)用。
?
這里只粘貼了部分代碼,具體代碼可以看下:https://github.com/xiaojiesir/handwritingspringmvc
項(xiàng)目結(jié)構(gòu)
配置web.xml
使用servlet前,我們需要再web.xml中配置以下代碼
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><servlet><servlet-name>mvc</servlet-name><servlet-class>com.springframework.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>application.properties</param-value></init-param><!-- Servlet 就會(huì)在服務(wù)器啟動(dòng) 時(shí)執(zhí)行了。(注意:如果設(shè)置為負(fù)整數(shù)或者不配置,則不會(huì)在啟動(dòng) 服務(wù)器時(shí)執(zhí)行,而要等此Servlet 被調(diào)用時(shí)才會(huì)被執(zhí)行。 )--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>mvc</servlet-name><url-pattern>/*</url-pattern></servlet-mapping></web-app><url-pattern>/*</url-pattern> 這種攔截匹配規(guī)則其實(shí)是一種錯(cuò)誤方式,因?yàn)橹皇呛喴譻pringmvc框架,不需要jsp,所以沒問題。具體可以百度了解這方面知識(shí)。
實(shí)現(xiàn)init方法
@Overridepublic void init(ServletConfig config) throws ServletException {System.out.println("init方法");//1.加載配置文件 doLoadCongig(config.getInitParameter(LOCATION));//2.掃描所有相關(guān)的類doScanner(p.getProperty("scanPackage"));//3.初始化所有的相關(guān)類的實(shí)例,并保存到IOC容器中 doInstance();//4.依賴注入 doAutowired();//5.構(gòu)造HandlerMapping initHandlerMapping();//6.等待請(qǐng)求,匹配URL,定位方法,反射調(diào)用執(zhí)行//調(diào)用doGet或者doPost方法//提示信息System.out.println("my springmvc is success");}init方法中的1.2.3.4可以參考之前手寫spring中的代碼,我詳細(xì)講解下5
第五步遍歷容器中的bean,利用@MyRequestMapping注解將url與方法做映射
private void initHandlerMapping() {if (ioc.isEmpty()) {return;}try {for (Entry<String, Object> entry : ioc.entrySet()) {Class<? extends Object> clazz = entry.getValue().getClass();if (!clazz.isAnnotationPresent(MyController.class)) {continue;}// 拼url時(shí),是controller頭的url拼上方法上的urlString baseUrl = "";if (clazz.isAnnotationPresent(MyRequestMapping.class)) {MyRequestMapping annotation = clazz.getAnnotation(MyRequestMapping.class);baseUrl = annotation.value();}Method[] methods = clazz.getMethods();for (Method method : methods) {if (!method.isAnnotationPresent(MyRequestMapping.class)) {continue;}MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);String url = annotation.value();url = (baseUrl + "/" + url).replaceAll("/+", "/");handlerMapping.put(url, method);System.out.println(url + "," + method);}}} catch (Exception e) {e.printStackTrace();}}實(shí)現(xiàn)dopost方法
根據(jù)請(qǐng)求url,獲取method,根據(jù)@MyRequestParam注解獲取方法參數(shù)并賦值,利用反射執(zhí)行方法
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// TODO Auto-generated method stubtry {System.out.println("doPost");doDispatch(req,resp);//未采用策略模式//doDispatchDesignPatterns(req,resp);//采用策略模式} catch (Exception e) {// TODO Auto-generated catch block e.printStackTrace();} }未采用策略模式,參數(shù)類型使用if else if判斷類型,
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {// TODO Auto-generated method stubif(this.handlerMapping.isEmpty()){return;}String url =req.getRequestURI();// /myspringmvc/demo/userString contextPath = req.getContextPath();// /myspringmvcurl = url.replace(contextPath, "").replaceAll("/+", "/");if(!this.handlerMapping.containsKey(url)){resp.getWriter().write("404 Not Found!!");return;}Map<String,String[]> params = req.getParameterMap();Method method =this.handlerMapping.get(url);//獲取方法的參數(shù)列表Class<?>[] paramerterTypes = method.getParameterTypes();//獲取請(qǐng)求的參數(shù)Map<String,String[]> parameterMap = req.getParameterMap();//保留參數(shù)值Object[] paramValues = new Object[paramerterTypes.length];//方法的參數(shù)列表for (int i = 0; i < paramerterTypes.length; i++) {//根據(jù)參數(shù)名稱,做某些處理Class parameterType =paramerterTypes[i];if(parameterType == HttpServletRequest.class){//參數(shù)類型已明確,這邊強(qiáng)轉(zhuǎn)類型paramValues[i] =req;continue;}else if(parameterType == HttpServletResponse.class){paramValues[i] = resp;continue;}else if(parameterType == String.class){//獲取當(dāng)前方法的參數(shù)Annotation[][] an = method.getParameterAnnotations();//個(gè)數(shù)和paramerterTypes.length一樣Annotation[] paramAns = an[i];for (Annotation paramAn : paramAns) {//判斷傳進(jìn)的paramAn.getClass()是不是 MyRequestParam 類型if (MyRequestParam.class.isAssignableFrom(paramAn.getClass())) {MyRequestParam cr = (MyRequestParam) paramAn;String value = cr.value();paramValues[i] = req.getParameter(value);}}}}try {//String beanName = lowerFirstCase(method.getDeclaringClass().getSimpleName());//獲取源代碼中給出的‘底層類’簡稱String beanName = "/" + url.split("/")[1];method.invoke(this.ioc.get(beanName), paramValues);} catch (Exception e) {// TODO: handle exception e.printStackTrace();}}采用策略模式
private void doDispatchDesignPatterns(HttpServletRequest req, HttpServletResponse resp) {// 通過req獲取請(qǐng)求的url /myspringmvc/demo/userString url = req.getRequestURI();// /myspringmvcString context = req.getContextPath();// /demo/userString path = url.replaceAll(context, "");// 通過當(dāng)前的path獲取handlerMap的方法名Method method = this.handlerMapping.get(path);// 獲取beans容器中的beanObject instance = this.ioc.get("/" + path.split("/")[1]);// 處理參數(shù)HandlerAdapterService ha = (HandlerAdapterService) this.ioc.get("myHandlerAdapter"); Object[] args = ha.handle(req, resp, method, ioc);// 通過反射來實(shí)現(xiàn)方法的調(diào)用try {method.invoke(instance, args);} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}處理參數(shù)接口
package com.xiaojiesir.demo.handlerAdapter;import java.lang.reflect.Method; import java.util.Map;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public interface HandlerAdapterService {public Object[] handle(HttpServletRequest req, HttpServletResponse resp,Method method, Map<String, Object> beans); }處理參數(shù)的實(shí)現(xiàn)類
import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import com.springframework.annotation.MyService; import com.xiaojiesir.demo.argumentResolver.ArgumentResolver;@MyService("myHandlerAdapter") public class MyHandlerAdapter implements HandlerAdapterService {@Overridepublic Object[] handle(HttpServletRequest req, HttpServletResponse resp, Method method, Map<String, Object> beans) {// TODO Auto-generated method stub//獲取方法中含義的參數(shù)Class<?>[] paramClazzs = method.getParameterTypes();System.out.println("======當(dāng)前需要解析的參數(shù)對(duì)應(yīng)的類=========");for(Class<?> clazz: paramClazzs) {System.out.println(clazz);}// 定義一個(gè)返回參數(shù)的結(jié)果集Object[] args = new Object[paramClazzs.length]; // Object[] args = {req, resp, "name", "xiaojiesir"};// 定義一個(gè)ArgumentResolver實(shí)現(xiàn)類的MapMap<String, Object> argumentResolvers = getBeansOfType(beans, ArgumentResolver.class);System.out.println("======當(dāng)前需要解析的參數(shù)對(duì)應(yīng)的類實(shí)例化=========");for(Map.Entry<String, Object> map: argumentResolvers.entrySet()) {System.out.println("key:" + map.getKey() + "; value:" + map.getValue());}//定義參數(shù)索引int paramIndex = 0;//定義數(shù)組下標(biāo)索引int i = 0; // 開始處理參數(shù)for(Class<?> paramClazz: paramClazzs) {//哪個(gè)參數(shù)對(duì)應(yīng)了哪個(gè)參數(shù)解析類,用策略模式來找for (Map.Entry<String, Object> entry : argumentResolvers.entrySet()) {ArgumentResolver ar = (ArgumentResolver)entry.getValue();if (ar.support(paramClazz, paramIndex, method)) {args[i++] = ar.argumentResolver(req,resp,paramClazz,paramIndex,method);}}paramIndex++;}return args;}/*** @param beans IOC容器中全部的bean* @param intfType 定義的ArgumentResolver類* @return*/private Map<String, Object> getBeansOfType(Map<String, Object> beans,Class<ArgumentResolver> intfType) {Map<String, Object> resultBeans = new HashMap<>();for(Map.Entry<String, Object> map: beans.entrySet()) {// 獲取滿足ArgumentResolver接口的beanClass<?>[] intfs = map.getValue().getClass().getInterfaces();if(intfs != null && intfs.length >0) {for(Class<?> intf: intfs) {// 將滿足的bean存儲(chǔ)在resultBeans中if(intf.isAssignableFrom(intfType)) {resultBeans.put(map.getKey(), map.getValue());}}}}return resultBeans;}}參數(shù)接口
import java.lang.reflect.Method;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public interface ArgumentResolver {/*** 判斷當(dāng)前的類是繼承于ArgumentResolver* @param type 當(dāng)前參數(shù)注解的類對(duì)象* @param paramIndex 參數(shù)下標(biāo)* @param method 當(dāng)前的方法* @return*/public boolean support(Class<?> type, int paramIndex, Method method);/*** * @param request* @param response* @param type* @param paramIndex* @param method* @return*/public Object argumentResolver(HttpServletRequest request,HttpServletResponse response, Class<?> type, int paramIndex,Method method); }處理Request請(qǐng)求參數(shù)
import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import com.springframework.annotation.MyService;/** 處理Request請(qǐng)求參數(shù)*/ @MyService("httpServletRequestArgumentResolver") public class HttpServletRequestArgumentResolver implements ArgumentResolver {@Overridepublic boolean support(Class<?> type, int paramIndex, Method method) {return ServletRequest.class.isAssignableFrom(type);}@Overridepublic Object argumentResolver(HttpServletRequest request,HttpServletResponse response, Class<?> type, int paramIndex,Method method) {return request;}}處理Response參數(shù)
import java.lang.reflect.Method;import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import com.springframework.annotation.MyService; /** 處理Response參數(shù)*/ @MyService("httpServletResponseArgumentResolver") public class HttpServletResponseArgumentResolver implements ArgumentResolver {@Overridepublic boolean support(Class<?> type, int paramIndex, Method method) {return ServletResponse.class.isAssignableFrom(type);}@Overridepublic Object argumentResolver(HttpServletRequest request,HttpServletResponse response, Class<?> type, int paramIndex,Method method) {return response;}}處理自定義的參數(shù)
import java.lang.annotation.Annotation; import java.lang.reflect.Method;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import com.springframework.annotation.MyRequestParam; import com.springframework.annotation.MyService;@MyService("requestParamArgumentResolver") public class RequestParamArgumentResolver implements ArgumentResolver {@Overridepublic boolean support(Class<?> type, int paramIndex, Method method) {// type = class java.lang.String// @MyRequestParam("name")String name//獲取當(dāng)前方法的參數(shù)Annotation[][] an = method.getParameterAnnotations();Annotation[] paramAns = an[paramIndex];for (Annotation paramAn : paramAns) {//判斷傳進(jìn)的paramAn.getClass()是不是 MyRequestParam 類型if (MyRequestParam.class.isAssignableFrom(paramAn.getClass())) {return true;}}return false;}@Overridepublic Object argumentResolver(HttpServletRequest request,HttpServletResponse response, Class<?> type, int paramIndex,Method method) {//獲取當(dāng)前方法的參數(shù)Annotation[][] an = method.getParameterAnnotations();Annotation[] paramAns = an[paramIndex];for (Annotation paramAn : paramAns) {//判斷傳進(jìn)的paramAn.getClass()是不是 MyRequestParam 類型if (MyRequestParam.class.isAssignableFrom(paramAn.getClass())) {MyRequestParam cr = (MyRequestParam) paramAn;String value = cr.value();return request.getParameter(value);}}return null;}}啟動(dòng)服務(wù),在URL輸入請(qǐng)求地址:
http://localhost:8080/myspringmvc/demo/user?name=xiaojiesir123&id=1
?
總結(jié):
手寫的spring和springmvc主要用了反射、注解。正式的spring中還有很多設(shè)計(jì)模式,值得我們學(xué)習(xí)。所以我們?cè)谡莆栈A(chǔ)知識(shí)后,多讀框架的源碼,獲取框架中的設(shè)計(jì)模式,設(shè)計(jì)理念更助于提升自己。
?
轉(zhuǎn)載于:https://www.cnblogs.com/xiaojiesir/p/11157235.html
總結(jié)
以上是生活随笔為你收集整理的手写springmvc的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库课程设计报告——员工工资管理系统
- 下一篇: C++const的多种用法