摘要:網(wǎng)上很多關(guān)于的分析,但很少有手動(dòng)實(shí)現(xiàn)的,這里通過(guò)一個(gè)簡(jiǎn)單的實(shí)現(xiàn)基本功能,僅供學(xué)習(xí)參考。下面編寫一個(gè)和測(cè)試下代碼如下代碼如下請(qǐng)求學(xué)習(xí)交流,歡迎加群
網(wǎng)上很多關(guān)于springmvc的分析,但很少有手動(dòng)實(shí)現(xiàn)的,這里通過(guò)一個(gè)簡(jiǎn)單的demo實(shí)現(xiàn)mvc基本功能,僅供學(xué)習(xí)參考。
我們先簡(jiǎn)單了解下springmvc請(qǐng)求流程,如下圖:
從圖上得知,最先處理請(qǐng)求的是dispatcherServlet,它接受請(qǐng)求并查詢得到攔截器鏈HandlerExecutionChain,HandlerAdapter經(jīng)過(guò)適配器調(diào)用具體的處理器(Controller).
查看源碼可以到spring-webmvc.jar中,org.springframework.web.servlet/DispatcherServlet.class,其中方法doDispatch()完成了一個(gè)請(qǐng)求到返回?cái)?shù)據(jù)的完整操作.
下面我們開(kāi)始動(dòng)手了,先創(chuàng)建一個(gè)javaweb工程,寫一個(gè)Servlet,如下:
@WebServlet(urlPatterns = "/*", loadOnStartup = 1) public class DispatcherServlet extends HttpServlet { private ListclzList = new ArrayList<>(); private Map beansMap = new HashMap<>(); private Map urlMapping = new HashMap<>(); @Override public void init() throws ServletException { try { //掃描配置 這里是包名 scanPackages("com.iti.smvc"); //實(shí)例化對(duì)象 doInstance(); //建立對(duì)象之間的依賴ioc ioc(); //建立url到controller的映射 doMapping(); } catch (Exception e) { e.printStackTrace(); } } }
注:servlet3.0不再需要web.xml, 這里將成員變量寫入servlet并不是很好的實(shí)現(xiàn),會(huì)導(dǎo)致線程不安全
這個(gè)servlet要做一些初始化的工作,如:
1.掃描包名,將class對(duì)象裝入clzList列表
2.遍歷clzList列表,實(shí)例化有Controller和Service標(biāo)注的類
3.依賴注入,將service注入到controller
4.建立url與controller中方法url的mapping關(guān)系
我們依次來(lái)實(shí)現(xiàn)他們:
下面的是掃描配置方法
private void scanPackages(String packageUrl) { String fileUrl = getClass().getClassLoader().getResource("/"+packageUrl.replaceAll(".", "/")).getFile(); File scanfile = new File(fileUrl); String[] fileList = scanfile.list(); for (String fileName: fileList) { File file = new File(fileUrl+fileName); if (file.isDirectory()) { scanPackages(packageUrl + "." + fileName);; } else { clzList.add(packageUrl + "." + fileName.replace(".class", "")); } } }
接著是對(duì)象實(shí)例化:
private void doInstance() throws Exception{ if (clzList.size()>0) { for (String clzName : clzList) { Class> clzClass = Class.forName(clzName); if (clzClass.isAnnotationPresent(Controller.class)) { //for controller RequestMapping rm = clzClass.getAnnotation(RequestMapping.class); beansMap.put(rm.value(), clzClass.newInstance()); } else if (clzClass.isAnnotationPresent(Service.class)) { Service service = clzClass.getAnnotation(Service.class); beansMap.put(service.value(), clzClass.newInstance()); } } } }
接著是依賴注入,其實(shí)是反射:
private void ioc() throws Exception{ if (beansMap.size()>0) { for (Map.Entryentry : beansMap.entrySet()) { Field[] fields = entry.getValue().getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Autowired.class)) { Qualifier anno = field.getAnnotation(Qualifier.class); field.set(entry.getValue(), beansMap.get(anno.value())); } } } } }
最后是建立請(qǐng)求url與controller的mapping關(guān)系,如下:
private void doMapping() { if (beansMap.size()>0) { for (Map.Entryentry: beansMap.entrySet()) { Class extends Object> obj = entry.getValue().getClass(); if (obj.isAnnotationPresent(Controller.class)){ RequestMapping rm = obj.getAnnotation(RequestMapping.class); Method[] methods = obj.getMethods(); for (Method method: methods) { if (method.isAnnotationPresent(RequestMapping.class)) { RequestMapping anno = method.getAnnotation(RequestMapping.class); urlMapping.put(rm.value() + anno.value(), method); } } } } } }
還要把注解創(chuàng)建下:
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Controller { String value() default ""; } @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Qualifier { String value() default ""; } @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestMapping { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Service { String value() default ""; }
此時(shí)就可以啟動(dòng)服務(wù)完成初始化工作了
下面我們要?jiǎng)?chuàng)建一個(gè)sevice方法來(lái)接收url請(qǐng)求
@Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String requestURI = req.getRequestURI(); String contextPath = req.getContextPath(); //得到請(qǐng)求地址 String path = requestURI.replace(contextPath, ""); Method method = (Method)urlMapping.get(path); if (method != null) { try { Object obj = method.invoke(beansMap.get("/"+path.split("/")[1])); resp.getOutputStream().write(obj.toString().getBytes()); } catch (Exception e) { e.printStackTrace(); } } }
上面是得到請(qǐng)求url,然后從urlMapping得到要調(diào)用的method,再通過(guò)反射調(diào)用,最后通過(guò)outputStream輸出到瀏覽器上。
下面編寫一個(gè)controller和service測(cè)試下
controller代碼如下:
@Controller @RequestMapping("/hello") public class HelloController { @Autowired @Qualifier("helloservice") Helloservice helloservice; @RequestMapping("/sayHello") public String sayHello() { //System.out.println(helloservice.hello()); return "controller"; } }
service代碼如下:
@Service("helloservice") public class Helloservice { public String hello() { return "hello"; } }
請(qǐng)求url:http://localhost:8080/hello/sayHello
學(xué)習(xí)交流,歡迎加群:64691032
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/76973.html
摘要:引言剛考完期末,再也不用考試?yán)沧罱鼘W(xué)習(xí)了慕課網(wǎng)的實(shí)戰(zhàn)課手寫,劍指開(kāi)源框架靈魂。最近將本課程和看透結(jié)合起來(lái)學(xué)習(xí),感覺(jué)受益匪淺,同時(shí),糾正了我之前對(duì)的一些誤解。誤解洪荒時(shí)代的當(dāng)年,開(kāi)發(fā)都需要手動(dòng)去實(shí)現(xiàn)。為了解決太多的問(wèn)題,引入了,進(jìn)行統(tǒng)一調(diào)度。 引言 剛考完期末,再也不用考試?yán)玻。。?最近學(xué)習(xí)了慕課網(wǎng)的實(shí)戰(zhàn)課《手寫SpringMVC,劍指開(kāi)源框架靈魂》。 showImg(https://s...
摘要:也就是說(shuō)映射器就是用于處理什么樣的請(qǐng)求提交給處理。這和是一樣的提交參數(shù)的用戶名編號(hào)提交配置處理請(qǐng)求注冊(cè)映射器包框架接收參數(shù)設(shè)置無(wú)參構(gòu)造器,里邊調(diào)用方法,傳入要封裝的對(duì)象這里的對(duì)象就表示已經(jīng)封裝好的了對(duì)象了。 什么是SpringMVC? SpringMVC是Spring家族的一員,Spring是將現(xiàn)在開(kāi)發(fā)中流行的組件進(jìn)行組合而成的一個(gè)框架!它用在基于MVC的表現(xiàn)層開(kāi)發(fā),類似于struts...
摘要:只要有一個(gè)攔截器不放行,不能執(zhí)行完成號(hào)不放行和號(hào)不放行測(cè)試結(jié)果總結(jié)只有前邊的攔截器方法放行,下邊的攔截器的才執(zhí)行。至于他們的攔截器鏈的調(diào)用順序,和的是沒(méi)有差別的。 前言 本博文主要講解的知識(shí)點(diǎn)如下: 校驗(yàn)器 統(tǒng)一處理異常 RESTful 攔截器 Validation 在我們的Struts2中,我們是繼承ActionSupport來(lái)實(shí)現(xiàn)校驗(yàn)的...它有兩種方式來(lái)實(shí)現(xiàn)校驗(yàn)的功能 手寫...
摘要:接口聲明并實(shí)現(xiàn)接口聲明一個(gè)接口新建一個(gè)類,并實(shí)現(xiàn)接口單元測(cè)試單元測(cè)試是為了驗(yàn)證第步中接口的方法。中新增類使用實(shí)現(xiàn)單元測(cè)試指定注入的配置文件使用標(biāo)準(zhǔn)的注釋來(lái)告訴使用在中新增類文件運(yùn)行單元測(cè)試右鍵運(yùn)行結(jié)果到此,我們已經(jīng)搭建了一個(gè)基于的項(xiàng)目環(huán)境。 本文詳細(xì)講述如何搭建一個(gè)Spring+SpringMVC+Maven+Mybatis+MySQL項(xiàng)目環(huán)境。eclipse、maven 及 mysq...
閱讀 1585·2025-02-07 13:29
閱讀 1010·2024-11-07 18:25
閱讀 131506·2024-02-01 10:43
閱讀 1382·2024-01-31 14:58
閱讀 1150·2024-01-31 14:54
閱讀 83577·2024-01-29 17:11
閱讀 3880·2024-01-25 14:55
閱讀 2396·2023-06-02 13:36