手把手寫Spring框架
這部分目標(biāo)是MVC!
主要完成3個重要組件:
HandlerMapping:保存URL映射關(guān)系
HandlerAdapter:動態(tài)參數(shù)適配器
ViewResolvers:視圖轉(zhuǎn)換器,模板引擎
SpringMVC核心組件執(zhí)行流程:


相對應(yīng)的,用以下幾個類來實現(xiàn)上述的功能:

初始化階段
在DispatcherServlet這個類的init方法中,將mvc部分替換為initStrategies(context):

并且調(diào)用初始化三個組件的方法。
分別完善這幾個方法:
private void initViewResolvers(PigApplicationContext context) {
//模板引擎的根路徑
String tempateRoot = context.getConfig().getProperty("templateRoot");
String templateRootPath = this.getClass().getClassLoader().getResource(tempateRoot).getFile();
File templateRootDir = new File(templateRootPath);
for (File file : templateRootDir.listFiles()) {
this.viewResolvers.add(new PIGViewResolver(tempateRoot));
}
}
private void initHandlerAdapters(PigApplicationContext context) {
for (PIGHandlerMapping handlerMapping : handlerMappings) {
this.handlerAdapters.put(handlerMapping,new PIGHandlerAdapter());
}
}
private void initHandlerMappings(PigApplicationContext context) {
if(context.getBeanDefinitionCount() == 0){ return; }
String [] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
Object instance = context.getBean(beanName);
Class<?> clazz = instance.getClass();
if(!clazz.isAnnotationPresent(PIGController.class)){ continue; }
String baseUrl = "";
if(clazz.isAnnotationPresent(PIGRequestMapping.class)){
PIGRequestMapping requestMapping = clazz.getAnnotation(PIGRequestMapping.class);
baseUrl = requestMapping.value();
}
//默認(rèn)只獲取public方法
for (Method method : clazz.getMethods()) {
if(!method.isAnnotationPresent(PIGRequestMapping.class)){continue;}
PIGRequestMapping requestMapping = method.getAnnotation(PIGRequestMapping.class);
// //demo//query
String regex = ("/" + baseUrl + "/" + requestMapping.value().replaceAll("\\*",".*")).replaceAll("/+","/");
Pattern pattern = Pattern.compile(regex);
handlerMappings.add(new PIGHandlerMapping(pattern,instance,method));
System.out.println("Mapped " + regex + "," + method);
}
}
}
全局變量:
private List<PIGHandlerMapping> handlerMappings = new ArrayList<PIGHandlerMapping>();
private Map<PIGHandlerMapping,PIGHandlerAdapter> handlerAdapters = new HashMap<PIGHandlerMapping, PIGHandlerAdapter>();
private List<PIGViewResolver> viewResolvers = new ArrayList<PIGViewResolver>();
HandlerMapping與HandlerAdapter是一一對應(yīng)的關(guān)系。
運(yùn)行階段
整體思路:

getHandler就是通過請求拿到URI,并與handlerMappings中存好的模板進(jìn)行匹配:
private PIGHandlerMapping getHandler(HttpServletRequest req) {
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replaceAll(contextPath,"").replaceAll("/+","/");
for (PIGHandlerMapping handlerMapping : this.handlerMappings) {
Matcher matcher = handlerMapping.getPattern().matcher(url);
if(!matcher.matches()){continue;}
return handlerMapping;
}
return null;
}
HandlerAdapter
HandlerAdapter的handle方法負(fù)責(zé)反射調(diào)用具體方法。需要匹配參數(shù),那么需要先保存好實參和形參列表。
形參列表:編譯后就能拿到值
Map<String,Integer> paramIndexMapping = new HashMap<String, Integer>();
//提取加了PIGRequestParam注解的參數(shù)的位置
Annotation[][] pa = handler.getMethod().getParameterAnnotations();
for (int i = 0; i < pa.length; i ++){
for (Annotation a : pa[i]) {
if(a instanceof PIGRequestParam){
String paramName = ((PIGRequestParam) a).value();
if(!"".equals(paramName.trim())){
paramIndexMapping.put(paramName,i);
}
}
}
}
//提取request和response的位置
Class<?> [] paramTypes = handler.getMethod().getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
Class<?> type = paramTypes[i];
if(type == HttpServletRequest.class || type == HttpServletResponse.class){
paramIndexMapping.put(type.getName(),i);
}
}
實參列表:要運(yùn)行時才能拿到值
Map<String,String[]> paramsMap = req.getParameterMap();
//聲明實參列表
Object [] parameValues = new Object[paramTypes.length];
for (Map.Entry<String,String[]> param : paramsMap.entrySet()) {
String value = Arrays.toString(paramsMap.get(param.getKey()))
.replaceAll("\\[|\\]","")
.replaceAll("\\s","");
if(!paramIndexMapping.containsKey(param.getKey())){continue;}
int index = paramIndexMapping.get(param.getKey());
parameValues[index] = caseStringVlaue(value,paramTypes[index]);
}
if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){
int index = paramIndexMapping.get(HttpServletRequest.class.getName());
parameValues[index] = req;
}
if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){
int index = paramIndexMapping.get(HttpServletResponse.class.getName());
parameValues[index] = resp;
}
最后反射

總結(jié):

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
淺談Java內(nèi)存模型之happens-before
于存在線程本地內(nèi)存和主內(nèi)存的原因,再加上重排序,會導(dǎo)致多線程環(huán)境下存在可見性的問題。那么我們正確使用同步、鎖的情況下,線程A修改了變量a何時對線程B可見?下面小編來簡單介紹下2019-05-05
idea springboot 修改css,jsp不重啟實現(xiàn)頁面更新的問題
這篇文章主要介紹了idea springboot 修改css,jsp不重啟實現(xiàn)頁面更新的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
SpringBoot @FixMethodOrder 如何調(diào)整單元測試順序
這篇文章主要介紹了SpringBoot @FixMethodOrder 調(diào)整單元測試順序方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
JavaWeb中struts2實現(xiàn)文件上傳下載功能實例解析
這篇文章主要介紹了JavaWeb中struts2文件上傳下載功能的實現(xiàn),在Web應(yīng)用系統(tǒng)開發(fā)中,文件上傳和下載功能是非常常用的功能,需要的朋友可以參考下2016-05-05
IDEA 中 maven 的 Lifecycle 和Plugins&n
IDEA 主界面右側(cè) Maven 標(biāo)簽欄有同樣的命令,比如 install,既在 Plugins 中存在,也在 Lifecycle中存在,到底選哪個?二者又有什么區(qū)別呢?下面小編給大家介紹下IDEA 中 maven 的 Lifecycle 和Plugins 的區(qū)別,感興趣的朋友一起看看吧2023-03-03
Java ArrayDeque實現(xiàn)Stack的功能
這篇文章主要介紹了Java ArrayDeque實現(xiàn)Stack功能的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-03-03
Springboot項目中單元測試時注入bean失敗的解決方案
這篇文章主要介紹了Springboot項目中單元測試時注入bean失敗的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11
MyBatis動態(tài)SQL實現(xiàn)配置過程解析
這篇文章主要介紹了MyBatis動態(tài)SQL實現(xiàn)配置過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03

