手寫SpringMVC-實戰篇
有了手寫SpringMVC的思路,不知道大家是否已經開始實現呢?現在就為大家開始以上一篇文章《手寫SpringMVC-思路篇》的思路來一步步的實現SpringMVC的手寫,讓大家也能在SpringMVC的實現上有個初步的認識。此篇文章可能有些長,希望大家可以一邊看,一邊動手按照提供的程式碼(此篇文章程式碼有些多)來實現。
一、先還是給大家看看程式碼的結構
上述的就是目前的服務端段程式碼,在專案的src->main->webapp->WEB-INF下建立一個web.xml檔案,在專案啟動的時候,載入web.xml檔案,注入DispatcherServlet,實現後續的例項注入和初始化,並實現web的URL訪問服務端,實現資料的響應。
二、考慮定義註解類
在SpringMVC的框架實現中,少不了一些基本的注入類,例如:@Controller、@RequestMapping、@RequestParam等等,在上一篇文章中,根據需要實現的程式碼塊,需要自定義一些註解類:
@CustomController
@CustomRequestMapping
@CustomQualifier
@CustomRequestParam
@CustomService
這些分別對應著Spring+SpringMVC呼叫的實現註解,我們現在手動來寫入這些註解。此處不過多的講述,大家可以看文章手寫SpringMVC-思路篇
package com.ygsoft.custom.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; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CustomController { String value() default ""; }
package com.ygsoft.custom.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;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomRequestMapping {
String value() default "";
}
package com.ygsoft.custom.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;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomQualifier {
String value() default "";
}
package com.ygsoft.custom.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;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomRequestParam {
String value() default "";
}
package com.ygsoft.custom.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;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomService {
String value() default "";
}
如果大家對註解定義不熟悉,最好去百度下,理解下如何自定義註解。
三、建立Controller和Service層
此部分和SpringMVC的實現程式碼一樣,只是這部分的註解都是上一步定義的註解類來實現。
Controller層:
package com.ygsoft.custom.controller;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ygsoft.custom.annotation.CustomController;
import com.ygsoft.custom.annotation.CustomQualifier;
import com.ygsoft.custom.annotation.CustomRequestMapping;
import com.ygsoft.custom.annotation.CustomRequestParam;
import com.ygsoft.custom.service.MyService;
@CustomController
@CustomRequestMapping("/custom")
public class MyController {
@CustomQualifier("MyServiceImpl")
private MyService myService;
@CustomRequestMapping("/query")
public void query(HttpServletRequest request, HttpServletResponse response,
@CustomRequestParam("name")String name, @CustomRequestParam("age")String age) {
PrintWriter pw;
try {
PrintWriter writer = response.getWriter();
String result = myService.query(name, age);
writer.write(result);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Service層:
package com.ygsoft.custom.service;
public interface MyService {
public String query(String name, String age);
}
Service的impl層:
package com.ygsoft.custom.service.impl;
import com.ygsoft.custom.annotation.CustomService;
import com.ygsoft.custom.service.MyService;
@CustomService("MyServiceImpl")
public class MyServiceImpl implements MyService{
@Override
public String query(String name, String age) {
return "name:" + name + ";age:" + age;
}
}
四、建立DispatcherServlet類,並通過web.xml載入
web.xml:載入我們自己寫的MyDispatcherServlet和讀取配置檔案。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>maven_handmvc</display-name>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.ygsoft.custom.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
DispatcherServlet:本質上,我們自定義的DispatcherServlet是繼承了HttpServlet,主要是實現init()、doGet()、doPost()方法,init()方法,就是初始化基本的beans,並例項化controller層中的定義的service的變數,同時實現對映URL請求的Path和方法;doGet()、doPost()目前給的是doGet()呼叫doPost(),所以doPost()主要是實現引數的解析,並通過反射的機制實現方法的呼叫。
package com.ygsoft.custom.servlet;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
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 com.ygsoft.custom.annotation.CustomController;
import com.ygsoft.custom.annotation.CustomQualifier;
import com.ygsoft.custom.annotation.CustomRequestMapping;
import com.ygsoft.custom.annotation.CustomService;
import com.ygsoft.custom.controller.MyController;
import com.ygsoft.custom.handlerAdapter.HandlerAdapterService;
public class DispatcherServlet extends HttpServlet {
// 存在當前載入的所有的類
List<String> classNames = new ArrayList<String>();
// 儲存IOC容器的MAP
Map<String, Object> beans = new HashMap<>();
// 儲存路徑和方法的對映關係
Map<String, Object> handlerMap = new HashMap<String, Object>();
public DispatcherServlet() {
System.out.println("DispatchServlet()........");
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("init()............");
// 1.掃描需要的例項化的類
doScanPackage("com.ygsoft.custom");
System.out.println("當前檔案下所有的class類.......");
for(String name: classNames) {
System.out.println(name);
}
// 2.例項化
doInstance();
System.out.println("當前例項化的物件資訊.........");
for(Map.Entry<String, Object> map: beans.entrySet()) {
System.out.println("key:" + map.getKey() + "; value:" + map.getValue());
}
// 3.將IOC容器中的service物件設定給controller層定義的field上
doIoc();
// 4.建立path與method的對映關係
handlerMapping();
System.out.println("Controller層的path和方法對映.........");
for(Map.Entry<String, Object> map: handlerMap.entrySet()) {
System.out.println("key:" + map.getKey() + "; value:" + map.getValue());
}
}
private void doScanPackage(String basePackage) {
URL resource = this.getClass().getClassLoader().getResource("/" + basePackage.replaceAll("\\.", "/"));
String fileStr = resource.getFile();
// System.out.println(fileStr);
File file = new File(fileStr);
String[] listFiles = file.list();
for(String path: listFiles) {
File filePath = new File(fileStr + path);
// 如果當前是目錄,則遞迴
if(filePath.isDirectory()) {
doScanPackage(basePackage + "." + path);
// 如果是檔案,則直接新增到classNames
} else {
classNames.add(basePackage + "." + filePath.getName());
}
}
}
// 通過儲存的classnames的類字串來反射例項化物件,並存儲與beans的Map中
// com.ygsoft.custom.annotation.CustomController.class =>com.ygsoft.custom.annotation.CustomController
private void doInstance() {
if(classNames.isEmpty()) {
System.out.println("doScanner Fail....");
}
// 開始例項化物件,通過反射來實現
for(String className: classNames) {
String cn = className.replaceAll(".class", "");
try {
Class<?> clazz = Class.forName(cn);
// 判斷當前類是否有註解CustomController類,獲取設定的CustomeRequestMapping的值
if(clazz.isAnnotationPresent(CustomController.class)) {
// 通過CustomeRequestMapping獲取值,作為beans的key
CustomRequestMapping requestMapping = clazz.getAnnotation(CustomRequestMapping.class);
String key = requestMapping.value();
// beans的vaue為例項化物件
Object value = clazz.newInstance();
beans.put(key, value);
// 判斷當前的類是否有註解CustomService(考慮Service層),獲取值
} else if(clazz.isAnnotationPresent(CustomService.class)) {
// 通過CustomService獲取值,作為beans的key
CustomService service = clazz.getAnnotation(CustomService.class);
String key = service.value();
// beans的vaue為例項化物件
Object value = clazz.newInstance();
beans.put(key, value);
} else {
continue;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void doIoc() {
if(beans.isEmpty()) {
System.out.println("no class is instance......");
return;
}
for(Map.Entry<String, Object> map: beans.entrySet()) {
// 獲取例項
Object instance = map.getValue();
// 獲取類
Class<?> clazz = instance.getClass();
// 如果當前是CustomController類,則獲取類中定義的field來設定其物件
if(clazz.isAnnotationPresent(CustomController.class)) {
// 獲取全部的成員變數
Field[] fields = clazz.getDeclaredFields();
for(Field field: fields) {
// 如果當前的成員變數使用註解CustomRequestMapping進行處理
if(field.isAnnotationPresent(CustomQualifier.class)) {
// 獲取當前成員變數的註解值
CustomQualifier qualifier = field.getAnnotation(CustomQualifier.class);
String value = qualifier.value();
// 由於此類成員變數設定為private,需要強行設定
field.setAccessible(true);
// 將beans的例項化物件賦值給當前的變數
try {
field.set(instance, beans.get(value));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
continue;
}
}
}
}
}
private void handlerMapping() {
if(beans.isEmpty()) {
System.out.println("no class is instance......");
return;
}
for(Map.Entry<String, Object> map: beans.entrySet()) {
// 獲取當前的物件
Object instance = map.getValue();
// 獲取當前的類
Class<?> clazz = instance.getClass();
// 獲取註解當前為Controller的類
if(clazz.isAnnotationPresent(CustomController.class)) {
// 獲取類上的路徑
CustomRequestMapping clazzRm = clazz.getAnnotation(CustomRequestMapping.class);
String clazzPath = clazzRm.value();
// 處理方法
Method[] methods = clazz.getMethods();
for(Method method: methods) {
// 判斷註解為RequestMapping
if(method.isAnnotationPresent(CustomRequestMapping.class)) {
// 獲取方法上的路徑
CustomRequestMapping methodRm = method.getAnnotation(CustomRequestMapping.class);
String methodPath = methodRm.value();
// 將類上的路徑+方法上的路徑 設定為key,方法設定為value
handlerMap.put(clazzPath + methodPath, method);
} else {
continue;
}
}
} else {
continue;
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("doGet()............");
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("doPost()............");
// 通過req獲取請求的uri /maven_handmvc/custom/query
String uri = req.getRequestURI();
// /maven_handmvc
String context = req.getContextPath();
String path = uri.replaceAll(context, "");
// 通過當前的path獲取handlerMap的方法名
Method method = (Method) handlerMap.get(path);
// 獲取beans容器中的bean
MyController instance = (MyController) beans.get("/" + path.split("/")[1]);
// 處理引數
HandlerAdapterService ha = (HandlerAdapterService) beans.get("customHandlerAdapter");
Object[] args = ha.handle(req, resp, method, beans);
// 通過反射來實現方法的呼叫
try {
method.invoke(instance, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public void destroy() {
System.out.println("destroy()............");
}
}
DispatcherServlet類的實現中涉及到下面幾個步驟:
- 在init方法中:
// 1.掃描需要的例項化的類
doScanPackage("com.ygsoft.custom");
// 2.例項化
doInstance();
// 3.將IOC容器中的service物件設定給controller層定義的field上
doIoc();
// 4.建立path與method的對映關係
handlerMapping();
- 在doGet()和doPost()中:
主要是處理方法的引數,其中使用了策略模式來實現引數的處理,具體的可以看後續的程式碼。
// 處理引數
HandlerAdapterService ha = (HandlerAdapterService) beans.get("customHandlerAdapter");
Object[] args = ha.handle(req, resp, method, beans);
// 通過反射來實現方法的呼叫
try {
method.invoke(instance, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
五、引數處理涉及的類
其實此部分的實現,可以不用這麼複雜,由於個人學習,想將設計模式-策略模式使用到此部分,所以就有了下面的程式碼,其實這部分大家認為理解比較困難,或者不好理解,大家可以使用簡單的方式來實現。
使用反射呼叫實現的程式碼為:method.invoke(instance, args); 其中涉及的引數變數為args,目前的實現中請求的引數為HttpServletRequest request, HttpServletResponse response,
@CustomRequestParam("name")String name, @CustomRequestParam("age")String age
可以通過Annotation[][] annotations = method.getParameterAnnotations();獲取所有的引數的註解 與Class<?>[] paramTypes = method.getParameterTypes();獲取所有引數的型別進行遍歷將args賦值,然後再通過上面的反射進行呼叫。
下面的程式碼是使用了策略模式來實現,大家可以借鑑,可以研究下。
HandlerAdapterService:定義一個處理引數介面
package com.ygsoft.custom.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);
}
CustomHandlerAdapter:處理引數的實現類
package com.ygsoft.custom.handlerAdapter;
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.ygsoft.custom.annotation.CustomService;
import com.ygsoft.custom.argumentResolver.ArgumentResolver;
@CustomService("customHandlerAdapter")
public class CustomHandlerAdapter implements HandlerAdapterService {
@Override
public Object[] handle(HttpServletRequest req, HttpServletResponse resp,
Method method, Map<String, Object> beans) {
//獲取方法中含義的引數
Class<?>[] paramClazzs = method.getParameterTypes();
System.out.println("======當前需要解析的引數對應的類=========");
for(Class<?> clazz: paramClazzs) {
System.out.println(clazz);
}
// 定義一個返回引數的結果集
Object[] args = new Object[paramClazzs.length];
// Object[] args = {req, resp, "chenyanwu", "20"};
// 定義一個ArgumentResolver實現類的Map
Map<String, Object> argumentResolvers = getBeansOfType(beans, ArgumentResolver.class);
System.out.println("======當前需要解析的引數對應的類例項化=========");
for(Map.Entry<String, Object> map: argumentResolvers.entrySet()) {
System.out.println("key:" + map.getKey() + "; value:" + map.getValue());
}
//定義引數索引
int paramIndex = 0;
//定義陣列下標索引
int i = 0;
// 開始處理引數
for(Class<?> paramClazz: paramClazzs) {
//哪個引數對應了哪個引數解析類,用策略模式來找
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介面的bean
Class<?>[] intfs = map.getValue().getClass().getInterfaces();
if(intfs != null && intfs.length >0) {
for(Class<?> intf: intfs) {
// 將滿足的bean儲存在resultBeans中
if(intf.isAssignableFrom(intfType)) {
resultBeans.put(map.getKey(), map.getValue());
}
}
}
}
return resultBeans;
}
}
引數類:
ArgumentResolver:
package com.ygsoft.custom.argumentResolver;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface ArgumentResolver {
/**
* 判斷當前的類是繼承於ArgumentResolver
* @param type 當前引數註解的類物件
* @param paramIndex 引數下標
* @param method 當前的方法
* @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);
}
HttpServletRequestArgumentResolver:處理Request請求引數
package com.ygsoft.custom.argumentResolver;
import java.lang.reflect.Method;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ygsoft.custom.annotation.CustomService;
@CustomService("httpServletRequestArgumentResolver")
public class HttpServletRequestArgumentResolver implements ArgumentResolver {
@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
return ServletRequest.class.isAssignableFrom(type);
}
@Override
public Object argumentResolver(HttpServletRequest request,
HttpServletResponse response, Class<?> type, int paramIndex,
Method method) {
return request;
}
}
HttpServletResponseArgumentResolver:處理Response引數
package com.ygsoft.custom.argumentResolver;
import java.lang.reflect.Method;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ygsoft.custom.annotation.CustomService;
@CustomService("httpServletResponseArgumentResolver")
public class HttpServletResponseArgumentResolver implements ArgumentResolver {
@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
return ServletResponse.class.isAssignableFrom(type);
}
@Override
public Object argumentResolver(HttpServletRequest request,
HttpServletResponse response, Class<?> type, int paramIndex,
Method method) {
return response;
}
}
RequestParamArgumentResolver:處理自定義的引數
package com.ygsoft.custom.argumentResolver;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ygsoft.custom.annotation.CustomRequestParam;
import com.ygsoft.custom.annotation.CustomService;
@CustomService("requestParamArgumentResolver")
public class RequestParamArgumentResolver implements ArgumentResolver {
@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
// type = class java.lang.String
// @CustomRequestParam("name")String name
//獲取當前方法的引數
Annotation[][] an = method.getParameterAnnotations();
Annotation[] paramAns = an[paramIndex];
for (Annotation paramAn : paramAns) {
//判斷傳進的paramAn.getClass()是不是 CustomRequestParam 型別
if (CustomRequestParam.class.isAssignableFrom(paramAn.getClass())) {
return true;
}
}
return false;
}
@Override
public Object argumentResolver(HttpServletRequest request,
HttpServletResponse response, Class<?> type, int paramIndex,
Method method) {
//獲取當前方法的引數
Annotation[][] an = method.getParameterAnnotations();
Annotation[] paramAns = an[paramIndex];
for (Annotation paramAn : paramAns) {
//判斷傳進的paramAn.getClass()是不是 CustomRequestParam 型別
if (CustomRequestParam.class.isAssignableFrom(paramAn.getClass())) {
CustomRequestParam cr = (CustomRequestParam) paramAn;
String value = cr.value();
return request.getParameter(value);
}
}
return null;
}
}
6.啟動服務,在URL輸入請求地址:
返回的結果為:
掃描關注:全棧工程師成長記
一個可以交流的平臺,目的是為了做一個影響最有影響力的人的平臺。
相關推薦
手寫SpringMVC-實戰篇
有了手寫SpringMVC的思路,不知道大家是否已經開始實現呢?現在就為大家開始以上一篇文章《手寫SpringMVC-思路篇》的思路來一步步的實現SpringMVC的手寫,讓大家也能在SpringMVC的實現上有個初步的認識。此篇文章可能有些長,希望大家可以一邊
手寫SpringMVC實戰,從Spring底層原始碼分析與設計
課程內容: 1,三分鐘熟悉Spring底層原始碼,你只需準備好鮮花即可; 2,Spring原始碼很可怕?那是因為你沒聽過James的課; 3,快速熟悉原始碼基礎,洞析SpringMVC與Spring框架關係; 4,@Controller,@Service這些註解算什麼,一
純手寫SpringMVC到SpringBoot框架專案實戰
引言 Spring Boot其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。 通過這種方式,springboot是一個快速整合第三方框架的,簡化了xml的配置,專案中再也不包含web.xml檔案了
轉載:手寫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
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中配
springMVC學習心得及手寫springMVC簡單實現
springMVC學習心得及手寫springMVC簡單實現 Spring 是一個企業級開發框架,為解決企業級專案開發過於複雜而建立的,框架的主要優勢之一就是分層架構,允許開發者自主選擇元件。 Spring 的兩大核心機制是 IoC(控制反轉)和 AOP(面向切面程式設計),從開發的角度
springmvc原理詳解(手寫springmvc)
最近在複習框架 在網上搜了寫資料 和原理 今天總結一下 希望能加深點映像 不足之處請大家指出 我就不畫流程圖了 直接通過程式碼來了解springmvc的執行機制和原理 回想用springmvc用到最多的是什麼?當然是controller和RequestMapping註解啦
手寫SpringMVC迷你版
步驟 實現思路: 配置階段 1:在web.xml檔案中配置相應的DispatcherServlet的類路徑 2:指定application.properties的檔案路徑
純手寫SpringMVC架構,用註解實現springmvc過程(動腦學院Jack老師課後自己練習的體會)
標籤: 1、第一步,首先搭建如下架構,其中,annotation中放置自己編寫的註解,主要包括service controller qualifier RequestMapping 第二步:完成對應的annotation: package com.cn.annotation; import java.
兩小時手寫springmvc框架
這篇文章是學習咕泡學院tom老師手寫一個spring框架視訊而來,程式碼基本複製原文,稍作修改。可以幫助我們理解springmvc實現的大致原理。 1、構建maven工程,只需要匯入javax.servlet-api的依賴。另外配置,直接通過tomcat外掛來啟動專案。
手寫SpringMVC (一) 簡要版,去除冗餘複雜程式碼,手寫Spring核心功能
github 地址 :https://github.com/yjy91913/jerry-mvcframework 只是閒來無事寫的簡化版,僅供大家理解SpringMvc的運作原理) 瞭解了springMVC的原始碼,寫一個功能簡單可以實現的springM
看看一個老程序員如何手寫SpringMVC!
精華 conf name isp com ner 容器 並保存 結果 人見人愛的Spring已然不僅僅只是一個框架了。如今,Spring已然成為了一個生態。但深入了解Spring的卻寥寥無幾。這裏,我帶大家一起來看看,我是如何手寫Spring的。我將結合對Spring十多年
純手寫SpringMVC框架,用註解實現springmvc過程
開發十年,就只剩下這套架構體系了! >>>
手寫ORM入門篇(一)
物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程式技術,用於實現面向物件程式語言裡不同型別系統的資料之間的轉換 [1] 。從效果上說,它其實是建立了一個可在程式語言裡使用的--“虛擬物件資料庫”。 面向物件是從軟
機器學習實戰(第二篇)-k-近鄰演算法開發手寫識別系統
上一篇文章中,我們學習了使用k近鄰演算法改進約會網站,實現了通過一些資料的輸入判斷人員屬於哪一個分類。但是上篇文章基於的資料都是我們能夠簡單理解的數字資訊,本篇文章我們在人不太容易看懂的資料上使用分類器。這篇文章中我們將一步步構造使用k-近鄰分類器的手寫識別系統。為了
手寫spring+springmvc+mybatis框架篇——Mybatis
整合Mybatis是本專案中的一個難點。實現功能:1 動態繫結使用者輸入引數2 Mybatis的resultType動態繫結返回實體類。3 在spring中的介面注入4 xml版本的mapper注入。 關於Mybatis的優秀文章給大家推薦兩個1 手寫簡化版mybatis
KNN 演算法-實戰篇-如何識別手寫數字
> **公號:碼農充電站pro** > **主頁:** 上篇文章介紹了[KNN 演算法的原理](https://www.cnblogs.com/codeshell/p/14072586.html),今天來介紹如何**使用KNN 演算法識別手寫數字**? ### 1,手寫數字資料集 手寫數字資料集是一個用