欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
深入底層,仿SpringMVC自己寫(xiě)框架


前言:


前面的文章我們介紹過(guò)如何自己寫(xiě)一個(gè)MyBatis框架:

深入底層,仿MyBatis自己寫(xiě)框架


今天我們來(lái)寫(xiě)一個(gè)SpringMVC框架,相比于寫(xiě)MyBatis框架,SpringMVC要簡(jiǎn)單一些,只需要xml解析+反射就可以完成,不需要jdk動(dòng)態(tài)代理。


廢話(huà)不多說(shuō),直接開(kāi)始摟干貨。


要自己寫(xiě)框架,必須理解框架的底層原理和運行機制。那么我們首先來(lái)回顧SpringMVC的實(shí)現原理。


SpringMVC實(shí)現原理:


核心組件:


1.DispatcherServlet:前端控制器,是整個(gè)流程控制的核心,控制其他組件的執行,統一調度,降低組件之間的耦合性,相當于總指揮。


2.Handler:處理器,完成具體業(yè)務(wù)邏輯,相當于Servlet或Action。


3.HandlerMapping:DispatcherServlet接收到請求之后,通過(guò)HandlerMapping將不同的請求分發(fā)到不同的Handler。


4.HandlerInterceptor:處理器攔截器,是一個(gè)接口,如果我們需要做一些攔截處理,可以來(lái)實(shí)現這個(gè)接口。


5.HandlerExecutionChain:處理器執行鏈,包括兩部分內容:Handler和HandlerInterceptor(系統會(huì )有一個(gè)默認的HandlerInterceptor,如果需要額外攔截處理,可以添加攔截器設置)。


6.HandlerAdapter:處理器適配器,Handler執行業(yè)務(wù)方法之前,需要進(jìn)行一系列的操作包括表單數據的驗證,數據類(lèi)型的轉換,將表單數據封裝到JavaBean等等,這一系列的操作,都是由HandlerAdapter來(lái)完成,DispatcherServlet通過(guò)HandlerAdapter執行不同的Handler。


7.ModelAndView:裝載了模型數據和視圖信息,作為Handler的處理結果,返回給DispatcherServlet。


8.ViewResolver:視圖解析器,DispatcherServlet通過(guò)它將邏輯視圖解析成物理視圖,最終將渲染結果響應給客戶(hù)端。


以上就是SpringMVC的核心組件。那么這些組件之間是如何進(jìn)行交互的呢?


我們來(lái)看SpringMVC的實(shí)現流程:


1.客戶(hù)端請求被DispatcherServlet(前端控制器)接收。


2.根據HandlerMapping映射到Handler。


3.生成Handler和HandlerInterceptor(如果有則生成)。


4.Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回給DispatcherServlet。


5.DispatcherServlet通過(guò)HandlerAdapter調用Handler的方法做業(yè)務(wù)邏輯處理。


6.返回一個(gè)ModelAndView對象給DispatcherServlet。


7.DispatcherServlet將獲取的ModelAndView對象傳給ViewResolver視圖解析器,將邏輯視圖解析成物理視圖View。


8.ViewResolver返回一個(gè)View給DispatcherServlet。


9.DispatcherServlet根據View進(jìn)行視圖渲染(將模型數據填充到視圖中)。


10.DispatcherServlet將渲染后的視圖響應給客戶(hù)端。



通過(guò)以上的分析,大致可以將SpringMVC流程理解如下:

首先需要一個(gè)前置控制器DispatcherServlet,作為整個(gè)流程的核心,由它去調用其他組件,共同完成業(yè)務(wù)。主要組件有兩個(gè):一是Controller,調用其業(yè)務(wù)方法Method,執行業(yè)務(wù)邏輯。二是ViewResolver視圖解析器,將業(yè)務(wù)方法的返回值解析為物理視圖+模型數據,返回客戶(hù)端。


我們自己寫(xiě)框架就按照這個(gè)思路來(lái)。


初始化工作:

1.根據Spring IOC的思路,需要將參與業(yè)務(wù)的對象全部創(chuàng )建并保存,供流程調用。所以首先我們需要創(chuàng )建Controller對象,HTTP請求是通過(guò)注解找到對應的Controller對象,所以我們需要將所有的Controller與其注解建立關(guān)聯(lián),很顯然,使用key-value結構的Map集合來(lái)保存最合適不過(guò)了,這樣就模擬了IOC容器。


2.Controller的Method也是通過(guò)注解與HTTP請求映射的,同樣的,我們需要將所有的Method與其注解建立關(guān)聯(lián),HTTP直接通過(guò)注解的值找到對應的Method,這里也用Map集合保存。


3.實(shí)例化視圖解析器。


初始化工作完成,接下來(lái)處理HTTP請求,業(yè)務(wù)流程如下:

1.DispatcherServlet接收請求,通過(guò)映射從IOC容器中獲取對應的Controller對象。

2.根據映射獲取Controller對象對應的Method。

3.調用Method,獲取返回值。

4.將返回值傳給視圖解析器,返回物理視圖。

5.完成頁(yè)面跳轉。


思路捋清楚了,接下來(lái)開(kāi)始寫(xiě)代碼,我們需要創(chuàng )建以下類(lèi):

1.MyDispatcherServlet:模擬DispatcherServlet。

2.MyController:模擬Controller注解。

3.MyRequestMapping:模擬RequestMapping注解。

4.MyViewResolver:模擬ViewResolver視圖解析器。


創(chuàng )建MyDispatcherServlet,init方法完成初始化:

1.將Controller與注解進(jìn)行關(guān)聯(lián),保存到iocContainer中。

哪些Controller是需要添加到iocContainer中的?

必須同時(shí)滿(mǎn)足兩點(diǎn):

1.springmvc.xml中配置掃描的類(lèi)。

2.類(lèi)定義處添加了注解。

注意這兩點(diǎn)必須同時(shí)滿(mǎn)足。


代碼思路:

(1)解析springmvc.xml。

(2)獲取component-scan標簽配置的包下的所有類(lèi)。

(3)判斷若這些類(lèi)添加了@MyController注解,則創(chuàng )建實(shí)例對象,并且保存到iocContainer。

(4)@MyRequestMapping的值為鍵,Controller對象為值。


2.將Controller中的Method與注解進(jìn)行關(guān)聯(lián),保存到handlerMapping中。

代碼思路:

(1)遍歷iocContainer中的Controller實(shí)例對象。

(2)遍歷每一個(gè)Controller對象的Method。

(3)判斷Method是否添加了@MyRequestMapping注解,若添加,則進(jìn)行映射并保存。

(4)保存到handlerMapping中,@MyRequestMapping的值為鍵,Method為值。


3.實(shí)例化ViewResolver。

代碼思路:

(1)解析springmvc.xml。

(2)根據bean標簽的class屬性獲取需要實(shí)例化的MyViewResolver。

(3)使用反射創(chuàng )建實(shí)例化對象,同時(shí)獲取prefix和suffix屬性,以及setter方法。

(4)使用反射調用setter方法給屬性賦值,完成MyViewResolver的實(shí)例化。


doPost方法處理HTTP請求:

1.解析HTTP,分別得到Controller和Method對應的uri。

2.通過(guò)uri分別在iocContainer和handlerMapping中獲取對應的Controller以及Method。

3.使用反射調用Method,執行業(yè)務(wù)方法,獲取結果。

4.結果傳給MyViewResolver進(jìn)行解析,返回真正的物理視圖(JSP頁(yè)面)。

5.完成JSP的頁(yè)面跳轉。




代碼:


1.創(chuàng )建MyController注解,作用目標為類(lèi)。


package com.southwind.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 自定義Controller注解
* @author southwind
*
*/

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyController {
   String value() default '';
}


2.創(chuàng )建MyRequestMapping注解,作用目標為類(lèi)和方法。


package com.southwind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 自定義RequestMapping注解
* @author southwind
*
*/

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRequestMapping {
   String value() default '';
}



3.創(chuàng )建MyDispatcherServlet,核心控制器,init完成初始化工作,doPost處理HTTP請求。


package com.southwind.servlet;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpRetryException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.southwind.annotation.MyController;
import com.southwind.annotation.MyRequestMapping;
import com.southwind.view.MyViewResolver;

/**
* DispatcherServlet
* @author southwind
*
*/

public class MyDispatcherServlet extends HttpServlet{

   //模擬IOC容器,保存Controller實(shí)例對象
   private Map iocContainer = new HashMap();
   //保存handler映射
   private Map handlerMapping = new HashMap();
   //自定視圖解析器
   private MyViewResolver myViewResolver;

   @Override
   public void init(ServletConfig config) throws ServletException {
       // TODO Auto-generated method stub
       //掃描Controller,創(chuàng )建實(shí)例對象,并存入iocContainer
       scanController(config);
       //初始化handler映射
       initHandlerMapping();
       //加載視圖解析器
       loadViewResolver(config);
   }

   /**
    * 掃描Controller
    * @param config
    */

   public void scanController(ServletConfig config){
       SAXReader reader = new SAXReader();
       try {
           //解析springmvc.xml
           String path = config.getServletContext().getRealPath('')+'\\WEB-INF\\classes\\'+config.getInitParameter('contextConfigLocation');  
           Document document = reader.read(path);
           Element root = document.getRootElement();
           Iterator iter = root.elementIterator();
           while(iter.hasNext()){
               Element ele = (Element) iter.next();
               if(ele.getName().equals('component-scan')){
                   String packageName = ele.attributeValue('base-package');
                   //獲取base-package包下的所有類(lèi)名
                   List list = getClassNames(packageName);
                   for(String str:list){
                       Class clazz = Class.forName(str);
                       //判斷是否有MyController注解
                       if(clazz.isAnnotationPresent(MyController.class)){
                           //獲取Controller中MyRequestMapping注解的value
                           MyRequestMapping annotation = (MyRequestMapping) clazz.getAnnotation(MyRequestMapping.class);
                           String value = annotation.value().substring(1);
                           //Controller實(shí)例對象存入iocContainer
                           iocContainer.put(value, clazz.newInstance());
                       }
                   }
               }
           }
       } catch (Exception e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
   }

   /**
    * 獲取包下的所有類(lèi)名
    * @param packageName
    * @return
    */

   public List getClassNames(String packageName){
       List classNameList = new ArrayList();
       String packagePath = packageName.replace('.', '/');  
       ClassLoader loader = Thread.currentThread().getContextClassLoader();  
       URL url = loader.getResource(packagePath);  
       if(url != null){
           File file = new File(url.getPath());  
           File[] childFiles = file.listFiles();
           for(File childFile : childFiles){
               String className = packageName+'.'+childFile.getName().replace('.class', '');
               classNameList.add(className);
           }
       }
       return classNameList;
   }

   /**
    * 初始化handler映射
    */

   public void initHandlerMapping(){
       for(String str:iocContainer.keySet()){
           Class clazz = iocContainer.get(str).getClass();
           Method[] methods = clazz.getMethods();
              for (Method method : methods) {
                //判斷方式是否添加MyRequestMapping注解
                if(method.isAnnotationPresent(MyRequestMapping.class)){
                    //獲取Method中MyRequestMapping注解的value
                    MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
                    String value = annotation.value().substring(1);
                    //method存入methodMapping
                    handlerMapping.put(value, method);
                }
            }
       }
   }

   /**
    * 加載自定義視圖解析器
    * @param config
    */

   public void loadViewResolver(ServletConfig config){
       SAXReader reader = new SAXReader();
       try {
           //解析springmvc.xml
           String path = config.getServletContext().getRealPath('')+'\\WEB-INF\\classes\\'+config.getInitParameter('contextConfigLocation');  
           Document document = reader.read(path);
           Element root = document.getRootElement();
           Iterator iter = root.elementIterator();
           while(iter.hasNext()){
               Element ele = (Element) iter.next();
               if(ele.getName().equals('bean')){
                   String className = ele.attributeValue('class');
                   Class clazz = Class.forName(className);
                   Object obj = clazz.newInstance();
                   //獲取setter方法
                   Method prefixMethod = clazz.getMethod('setPrefix', String.class);
                   Method suffixMethod = clazz.getMethod('setSuffix', String.class);
                   Iterator beanIter = ele.elementIterator();
                   //獲取property值
                   Map propertyMap = new HashMap();
                   while(beanIter.hasNext()){
                       Element beanEle = (Element) beanIter.next();
                       String name = beanEle.attributeValue('name');
                       String value = beanEle.attributeValue('value');
                       propertyMap.put(name, value);
                   }
                   for(String str:propertyMap.keySet()){
                       //反射機制調用setter方法,完成賦值。
                       if(str.equals('prefix')){
                           prefixMethod.invoke(obj, propertyMap.get(str));
                       }
                       if(str.equals('suffix')){
                           suffixMethod.invoke(obj, propertyMap.get(str));
                       }
                   }
                   myViewResolver = (MyViewResolver) obj;
               }
           }
       } catch (Exception e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
   }

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
           throws ServletException, IOException
{
       // TODO Auto-generated method stub
       this.doPost(req, resp);
   }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
           throws ServletException, IOException
{
       // TODO Auto-generated method stub
       //獲取請求
       String handlerUri = req.getRequestURI().split('/')[2];
       //獲取Controller實(shí)例
       Object obj = iocContainer.get(handlerUri);
       String methodUri = req.getRequestURI().split('/')[3];
       //獲取業(yè)務(wù)方法
       Method method = handlerMapping.get(methodUri);
       try {
           //反射機制調用業(yè)務(wù)方法
           String value = (String) method.invoke(obj);
           //視圖解析器將邏輯視圖轉換為物理視圖
           String result = myViewResolver.jspMapping(value);
           //頁(yè)面跳轉
           req.getRequestDispatcher(result).forward(req, resp);
       } catch (Exception e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
   }
}


4.創(chuàng )建視圖解析器MyViewResolver。


package com.southwind.view;

/**
* 自定義視圖解析器
* @author southwind
*
*/

public class MyViewResolver {
   private String prefix;
   private String suffix;
   public String getPrefix() {
       return prefix;
   }
   public void setPrefix(String prefix) {
       this.prefix = prefix;
   }
   public String getSuffix() {
       return suffix;
   }
   public void setSuffix(String suffix) {
       this.suffix = suffix;
   }

   public String jspMapping(String value){
       return this.prefix+value+this.suffix;
   }
}


5.創(chuàng )建TestController,處理業(yè)務(wù)請求。


package com.southwind.controller;

import com.southwind.annotation.MyController;
import com.southwind.annotation.MyRequestMapping;

@MyController
@MyRequestMapping(value = '/testController')
public class TestController {

   @MyRequestMapping(value = '/test')
   public String test(){
       System.out.println('執行test相關(guān)業(yè)務(wù)');
       return 'index';
   }

}


6.測試。




跳轉index.jsp,同時(shí)控制臺打印業(yè)務(wù)日志,訪(fǎng)問(wèn)成功。



源碼:


github

https://github.com/southwind9801/SpringMVCImitate.git





專(zhuān)業(yè) 熱愛(ài) 專(zhuān)注

致力于最高效的Java學(xué)習

Java大聯(lián)盟



掃描下方二維碼,加入Java大聯(lián)盟



本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
手寫(xiě)SpringMVC框架(簡(jiǎn)易版)
關(guān)于spring java.lang.IllegalArgumentException: Name for argument type [java.lang.String] 的錯誤
spring MVC配置詳解
學(xué)習SpringMVC
SpringMVC 深度解析@RequestMapping(一)
SpringMVC工作原理
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久