springMVC學習心得及手寫springMVC簡單實現
springMVC學習心得及手寫springMVC簡單實現
Spring 是一個企業級開發框架,為解決企業級專案開發過於複雜而建立的,框架的主要優勢之一就是分層架構,允許開發者自主選擇元件。
Spring 的兩大核心機制是 IoC(控制反轉)和 AOP(面向切面程式設計),從開發的角度講,我們使用 Spring 框架就是用它的 IoC 和 AOP。
什麼是AOP和IOC
IoC 是典型的工廠模式,通過工廠去注入物件
AOP 是代理模式的體現
- IOC也叫控制反轉 ,控制反轉是什麼意思呢?反轉的的誰? 在傳統開發中一半是有呼叫者建立物件例項,也就是是呼叫者主動new出來的,那麼IOC就是將這個建立物件例項的任務從呼叫者的手裡反轉到spring的IOC容器來執行,控制反轉主要是反轉的這個過程;
舉個例子:
傳統模式:以前去買菜需要自己帶籃子,去超市買完自己帶回家;
IOC模式:空手去超市就可以了,籃子超市已經給你準備好了,直接拿來用就好了. - 依賴注入(Dependency Injection,DI) 能實現在程式執行中,動態地向某個物件提供它所依賴的其它物件的功能。
SpringMVC的常用元件及功能 ;
- DispatcherServlet: 前端控制器,是整個流程控制的核心,控制其他元件的執行,統一排程,降低元件之間的耦合性,相當於總指揮。
- Handler:處理器,完成具體業務邏輯,相當於 Servlet 或 Action。
- HandlerMapping: DispatcherServlet 接收到請求之後,通過 HandlerMapping 將不同的請求分發到不同的 Handler。
- HandlerInterceptor:處理器攔截器,是一個介面,如果我們需要做一些攔截處理,可以來實現這個介面。
- HandlerExecutionChain:處理器執行鏈,包括兩部分內容,Handler 和 HandlerInterceptor(系統會有一個預設的 HandlerInterceptor,如果需要額外攔截處理,可以新增攔截器設定)。
- HandlerAdapter:處理器介面卡,Handler 執行業務方法之前,需要進行一系列的操作,包括表單資料的驗證、資料型別的轉換、將表單資料封裝到 JavaBean 等,這一系列的操作,都是由 HandlerAdapter 來完成,- DispatcherServlet 通過 HandlerAdapter 執行不同的 Handler。
- ModelAndView:裝載了模型資料和檢視資訊,作為 Handler 的處理結果,返回給 DispatcherServlet。
- ViewResolver:檢視解析器,DispatcherServlet 通過它將邏輯檢視解析成物理檢視,最終將渲染結果響應給客戶端。
Spring MVC 的實現流程
-
客戶端請求被 DispatcherServlet(前端控制器)接收
-
根據 HandlerMapping 對映到 Handler
生成 Handler 和 HandlerInterceptor(如果有則生成) -
Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式一併返回給 DispatcherServlet
-
DispatcherServlet 通過 HandlerAdapter 呼叫 Handler 的方法做業務邏輯處理
返回一個 ModelAndView 物件給 DispatcherServlet -
DispatcherServlet 將獲取的 ModelAndView 物件傳給 ViewResolver 檢視解析器,將邏輯檢視解析成物理檢視 View
-
ViewResolver 返回一個 View 給 DispatcherServlet
-
DispatcherServlet 根據 View 進行檢視渲染(將模型資料填充到檢視中)
-
DispatcherServlet 將渲染後的檢視響應給客戶端
-
看到上面的實現原理,可能會有這樣的擔心,Spring MVC 如此眾多的元件開發起來一定很麻煩吧?答案是否定的,Spring MVC 使用起來非常簡單,很多元件都由框架提供,作為開發者我們直接使用即可,並不需要自己手動編寫程式碼,真正需要開發者進行編寫的元件只有兩個: -
Handler,處理業務邏輯
-
View,JSP 做展示
Spring MVC 底層實現
一個 Spring MVC 框架,相比於 MyBatis 框架,Spring MVC 要簡單一些,只需要 XML 解析 + 反射就可以完成,不需要 JDK 動態代理。 強調文字
下面,來手寫一下springMVC的簡單實現,廢話不多說,直接上乾貨
要自己寫框架,必須理解框架的底層原理和執行機制,這部分在上一部分已經講過
1.MyDispatcherServlet
首先需要一個前置控制器 DispatcherServlet,作為整個流程的核心,由它去呼叫其他組
件,共同完成業務。主要元件有兩個:一是 Controller,呼叫其業務方法 Method,執行業務邏輯;
二是 ViewResolver 檢視解析器,將業務方法的返回值解析為物理
檢視 + 模型資料,返回客戶端。
我們自己寫框架就按照這個思路來。
初始化工作
-
根據 Spring IoC 的思路,需要將參與業務的物件全部建立並儲存,供流程呼叫。因此,首先需要建立 Controller 物件,HTTP 請求是通過註解找到對應的 Controller 物件,我們需要將所有的 Controller 與其註解建立關聯,很顯然,使用 key-value 結構的 Map 集合來儲存最合適不過了,這樣就模擬了 IoC 容器。
-
Controller 的 Method 也是通過註解與 HTTP 請求對映的。同樣地,我們需要將所有的 Method 與其註解建立關聯,HTTP 直接通過註解的值找到對應的 Method,這裡也用 Map 集合儲存。
-
例項化檢視解析器
初始化工作完成,接下來處理 HTTP 請求,業務流程如下:
- DispatcherServlet 接收請求,通過對映從 IoC 容器中獲取對應的 Controller 物件;
- 根據對映獲取 Controller 物件對應的 Method;
- 呼叫 Method,獲取返回值;
- 將返回值傳給檢視解析器,返回物理檢視;
- 完成頁面跳轉。
建立類
思路捋清楚了,接下來開始寫程式碼,我們需要建立以下類。
- MyDispatcherServlet:模擬 DispatcherServlet
- MyController:模擬 Controller 註解
- MyRequestMapping:模擬 RequestMapping 註解
- MyViewResolver:模擬 ViewResolver 檢視解析器
- 建立 MyDispatcherServlet,init 方法完成初始化。
把 Controller 與註解進行關聯
將 Controller 與註解進行關聯,儲存到 iocContainer 中。哪些 Controller 是需要新增到 iocContainer 中的呢?必須同時滿足兩點: -
- springmvc.xml 中配置掃描的類
-
- 類定義處添加了註解
注意這兩點必須同時滿足。
- 類定義處添加了註解
(1)建立 MyController 註解,作用目標為類:
package morin.springmvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* controller註解 作用目標為類
* 作用範圍:執行時
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyController {
String value() default "";
}
(2)建立 MyRequestMapping 註解,作用目標為類和方法:
package morin.springmvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定義requestMapping註解,作用目標為類和方法,作用範圍為執行時
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRequestMapping {
String value() default "";
}
(3)建立 MyDispatcherServlet,核心控制器,init 完成初始化工作,doPost 處理 HTTP 請求:
package morin.springmvc.servlet;
import morin.springmvc.annotation.MyController;
import morin.springmvc.annotation.MyRequestMapping;
import morin.springmvc.view.MyViewResolver;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
/**
* MyDispathcerServlet class
*
* @author Molrin
* @date 2018/11/5 0005
*/
public class MyDispathcerServlet extends HttpServlet {
/**
* 模擬IDC容器,儲存bean物件
*/
private Map<String, Object> iocContainer = new HashMap<String, Object>();
/**
* 儲存handler對映
*/
private Map<String, Method> methods = new HashMap<String, Method>();
/**
* 檢視解析器
*/
private MyViewResolver myViewResolver;
@Override
public void init(ServletConfig config) throws ServletException {
//掃描Controller,建立例項物件,並存入iocContainer
scanController(config);
//初始化Handler對映
initHandlerMapping();
//載入檢視解析器
loadViewResolver(config);
}
/**
* 載入檢視解析器
* @param config 配置
*/
private void loadViewResolver(ServletConfig config) {
//建立SAXReader解析xml配置
SAXReader saxReader = new SAXReader();
try {
//解析springMVC.xml
String path = config.getServletContext().getRealPath("") + "\\WEB-INF\\classes\\" + config.getInitParameter("contextConfigLocation");
Document document = saxReader.read(path);
Element root = document.getRootElement();
Iterator iterator = root.elementIterator();
while (iterator.hasNext()) {
Element element = (Element) iterator.next();
if ("bean".equals(element.getName())) {
String className = element.attributeValue("class");
Class<?> aClass = Class.forName(className);
Object o = aClass.newInstance();
//獲取方法物件
Method setPrefix = aClass.getMethod("setPrefix", String.class);
Method setSuffix = aClass.getMethod("setSuffix", String.class);
Iterator beanIter = element.elementIterator();
//獲取property值
HashMap<String, String> map = new HashMap<String, String>();
while (beanIter.hasNext()) {
Element next = (Element) beanIter.next();
String name = next.attributeValue("name");
String value = next.attributeValue("value");
map.put(name, value);
}
for (String key : map.keySet()) {
//反射機制呼叫set方法,完成賦值
if ("prefix".equals(key)) {
setPrefix.invoke(o, map.get(key));
}
if ("suffix".equals(key)) {
setSuffix.invoke(o, map.get(key));
}
}
myViewResolver = (MyViewResolver)o;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始化handler對映
*/
private void initHandlerMapping() {
Set<String> keySet = iocContainer.keySet();
for (String value : keySet) {
//獲取每個類的class物件
Class<?> aClass = iocContainer.get(value).getClass();
//獲取該類的方法陣列
Method[] methods = aClass.getMethods();
for (Method method : methods) {
//判斷方法是否帶有MyRequestMapping註解
if (method.isAnnotationPresent(MyRequestMapping.class)) {
//獲取該註解中的值
MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
String ann = annotation.value().substring(1);
//將帶有註解的方法存入處理器對映器
this.methods.put(ann, method);
}
}
}
}
/**
* 掃描controller
*
* @param config 配置
*/
private void scanController(ServletConfig config) {
//建立解析xml物件
SAXReader saxReader = new SAXReader();
try {
//獲取xml路徑
String path = config.getServletContext().getRealPath("") + "\\WEB-INF\\classes\\" + config.getInitParameter("contextConfigLocation");
//獲取document
Document document = saxReader.read(path);
//獲取根元素
Element rootElement = document.getRootElement();
//獲取元素迭代器
Iterator iterator = rootElement.elementIterator();
//迴圈遍歷
while (iterator.hasNext()) {
//獲取單個元素
Element element = (Element) iterator.next();
//判斷是否有包掃描標籤
if ("component-scan".equals(element.getName())) {
//獲取掃描的包名
String basePackage = element.attributeValue("base-package");
//獲取basePackage包下的所有類名
List<String> classNames = getClassName(basePackage);
for (String className : classNames) {
//根據全限定名獲取class物件
Class<?> aClass = Class.forName(className);
//判斷是否有@Controller註解
if (aClass.isAnnotationPresent(MyController.class)) {
MyRequestMapping requestMapping = aClass.getAnnotation(MyRequestMapping.class);
//獲取該註解中的value
String value = requestMapping.value().substring(1);
//使用instance方法建立Controller物件並放入iocContainer
iocContainer.put(value, aClass.newInstance());
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private List<String> getClassName(String basePackage) {
//建立返回值
List<String> classNames = new ArrayList<String>();
//將全限定名中的. 全部替換為/
String newNames = basePackage.replace(".", "/");
//獲取當前執行緒的類載入器
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
URL url = contextClassLoader.getResource(newNames);
if (url != null) {
File file = new File(url.getPath());
//獲取該目錄下的所有檔案路徑的File物件集合
getFileName(file.listFiles(), basePackage,classNames);
}
return classNames;
}
private void getFileName(File[] file,String basePackage,List<String> classNames){
String path;
if (file != null) {
for (File file1 : file) {
if (!file1.isFile()) {
File[] files = file1.listFiles();
path = basePackage+"." +file1.getName();
getFileName(files,path,classNames);
}else {
path = basePackage + "." + file1.getName().replace(".class", "");
classNames.add(path);
}
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//獲取請求
String handlerUri = req.getRequestURI().split("/")[1];
//獲取controller例項
Object obj = iocContainer.get(handlerUri);
String methodUri = req.getRequestURI().split("/")[2];
//獲取method例項
Method method = methods.get(methodUri);
try {
//反射機制呼叫方法
String value = (String) method.invoke(obj,req.getParameter("sessionId"));
//檢視解析器將邏輯檢視轉換成物理檢視
String view = myViewResolver.jspMapping(value);
//頁面跳轉
req.getRequestDispatcher(view).forward(req, resp);
}catch (Exception e){
e.printStackTrace();
}
}
}
(4)建立檢視解析器 MyViewResolver:
package morin.springmvc.view;
/**
* MyViewResolver class
* 檢視解析器
* @author Molrin
* @date 2018/11/5 0005
*/
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 prefix+value+suffix;
}
}
(5)建立 TestController,處理業務請求:
package morin.springmvc.controller;
import morin.springmvc.annotation.MyController;
import morin.springmvc.annotation.MyRequestMapping;
import org.springframework.web.bind.annotation.CookieValue;
/**
* TestController class
*
* @author Molrin
* @date 2018/11/5 0005
*/
@MyController
@MyRequestMapping("/testController")
public class TestController {
@MyRequestMapping(value = "/test")
public String testHello(){
System.out.println("執行controller");
System.out.println("success!");
return "index";
}
}
(6)springMVC.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
相關推薦
springMVC學習心得及手寫springMVC簡單實現
springMVC學習心得及手寫springMVC簡單實現
Spring 是一個企業級開發框架,為解決企業級專案開發過於複雜而建立的,框架的主要優勢之一就是分層架構,允許開發者自主選擇元件。
Spring 的兩大核心機制是 IoC(控制反轉)和 AOP(面向切面程式設計),從開發的角度
java 手寫程式碼簡單模擬SpringMVC
######1.在Spring MVC中,將一個普通的java類標註上Controller註解之後,再將類中的方法使用RequestMapping註解標註,那麼這個普通的java類就夠處理Web請求
######2.通過一個簡單的java專案來模擬Spring MVC,先說一下整體思
轉載:手寫SpringMVC框架
javaee 作用 小寫 繼承 inf group css finally 減少
帶你手寫一個SpringMVC框架(有助於理解springMVC)
鏈接:https://my.oschina.net/liughDevelop
作者:我叫劉半仙
Spring
跟我一起造輪子 手寫springmvc
targe leg unit nco 容器 ner 並且 dir 有關 作為java程序員,項目中使用到的主流框架多多少少和spring有關聯,在面試的過程難免會問一些spring springmvc spring boot的東西,比如設計模式的使用、 怎麽實現spri
純手寫SpringMVC到SpringBoot框架專案實戰
引言
Spring Boot其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。
通過這種方式,springboot是一個快速整合第三方框架的,簡化了xml的配置,專案中再也不包含web.xml檔案了
springmvc流程圖 轉載 自己手寫一個SpringMVC框架
轉載 https://blog.csdn.net/lang_programmer/article/details/71598042 轉載 https://www.cnblogs.com/java1024/p/8556519.html 轉載 https://www.cnblogs.com
spring事務(6)-----手寫SpringMVC模式(手寫@RequestMapping和@Controller註解)
一,spring原生態的程式碼分析
1.1,首先,我們先來認識一下SpringMVC的主要元件
前端控制器(DisatcherServlet):接收請求,響應結果,返回可以是json,String等資料型別,也可以是頁面(Model)。
處理器對映器(HandlerMap
高手過招「效能優化/純手寫SpringMVC框架/MySql優化/微服務」
效能優化那些絕招,一般人我不告訴他
1,支付寶介面的介面如何正確呼叫;
2,從併發程式設計角度來提高系統性能;
3,系統響應的速度縮短N倍的祕密;
4,從Futuretask類原始碼分析到手寫;
5,快速提升Web專案吞吐量;
300行精華程式碼:純手寫SpringMVC框
手寫SpringMVC
相信用過SpringMVC的同學都會對它愛不釋手,它作為MVC框架使用起來簡直就是享受。時間久了相信會問它到底是怎麼實現的呢,今天我們來揭開其神祕的面紗。
這裡我們通過寫一個簡單的例子來模擬SpringMVC的基本原理,希望能夠對愛提問的人有所幫助
1.web.xml中配
學習筆記 利用反射 手寫一個簡單的實體類 轉json 的方法
不得不說 反射真的是個好動
# 貼上我的程式碼
package com.lengff.test;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetExce
機器學習實戰之K近鄰改進的約會網站程式碼及手寫字型識別程式碼
from numpy import *
import operator
import os
def createDataSet():
group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels=['A','A','B','B']
SpringMvc學習心得(三) spring例項化JavaBean的過程
我們一般是通過呼叫一個類的建構函式完成例項化的工作,spring當然也不例外。然而相比於直接通過建構函式對類進行例項化,spring的例項化過程要複雜得多。
在之前的部落格中,本人曾經說過,任何一個JavaBean都有一個beandefinition。然而b
springmvc原理詳解(手寫springmvc)
最近在複習框架 在網上搜了寫資料 和原理 今天總結一下 希望能加深點映像 不足之處請大家指出
我就不畫流程圖了 直接通過程式碼來了解springmvc的執行機制和原理
回想用springmvc用到最多的是什麼?當然是controller和RequestMapping註解啦
SpringMvc學習心得(二)spring註解配置原理淺析
除了使用xml檔案配置以外,spring還支援使用註解實現JavaBean的配置,其具體實現方式網上已經介紹的很詳細,這裡就不再贅述了。本文將主要通過原始碼解析spring註解配置JavaBean的全過程。這裡主要分析的是@component和@Autowired這兩個註解
手寫SpringMVC迷你版
步驟
實現思路:
配置階段
1:在web.xml檔案中配置相應的DispatcherServlet的類路徑
2:指定application.properties的檔案路徑
手寫SpringMVC實戰,從Spring底層原始碼分析與設計
課程內容:
1,三分鐘熟悉Spring底層原始碼,你只需準備好鮮花即可;
2,Spring原始碼很可怕?那是因為你沒聽過James的課;
3,快速熟悉原始碼基礎,洞析SpringMVC與Spring框架關係;
4,@Controller,@Service這些註解算什麼,一
機器學習與資料探勘-logistic迴歸及手寫識別例項的實現
本文主要介紹logistic迴歸相關知識點和一個手寫識別的例子實現
一、logistic迴歸介紹:
logistic迴歸演算法很簡單,這裡簡單介紹一下:
1、和線性迴歸做一個簡單的對比
下圖就是一個簡單的線性迴歸例項,簡單一點就是一個線性方程表示
(就是用來描述自變數和因
純手寫SpringMVC架構,用註解實現springmvc過程(動腦學院Jack老師課後自己練習的體會)
標籤:
1、第一步,首先搭建如下架構,其中,annotation中放置自己編寫的註解,主要包括service controller qualifier RequestMapping
第二步:完成對應的annotation:
package com.cn.annotation;
import java.
FPGA學習心得及(flash讀寫,+lwip+資料傳送等問題)
前段時間應老闆的專案需求,對硬體絲毫不懂得我開始接觸edk硬體程式設計,感覺這段時間跟硬體打交道,自己都老了不少。首先,硬體程式設計編譯很慢,編譯一次有時候得10-20分鐘,尤其是用verilog寫得程式比較大的時候。其次,除錯非常麻煩,不能像利用c或者c#那樣斷點除錯了,
手寫SpringMVC-實戰篇
有了手寫SpringMVC的思路,不知道大家是否已經開始實現呢?現在就為大家開始以上一篇文章《手寫SpringMVC-思路篇》的思路來一步步的實現SpringMVC的手寫,讓大家也能在SpringMVC的實現上有個初步的認識。此篇文章可能有些長,希望大家可以一邊