自己动手写一个spring之MVC_2

发布时间:2026/7/7 3:15:57
自己动手写一个spring之MVC_2 写在前面源码 。在前面的文章中controller层的bean我们并没有使用IOC容器管理起来并且DispatcherServlet的职责过去繁重了完全不符合单一职责的原则所以本文也会对DispatcherServlet进行拆解。1增加controller的IOC容器老规矩如下类publicclassXmlWebApplicationContextextendsClassPathXmlApplicationContextimplementsWebApplicationContext{privateServletContextservletContext;// ...}为了能够方便从contextloadlistenr创建的容器中获取bean信息我们可以引入父子容器的概念listener初始化的作为父容器controller的容器作为子容器这样如果controller中要获取service bean或其他的bean的时候就可以从父容器中获取了因此如下修改dispacherservletpackagecom.hc.minispring.web.v4_split_dispatcher;publicclassDispatcherServletextendsHttpServlet{// ...privateWebApplicationContextwebApplicationContext;privateWebApplicationContextparentApplicationContext;// ...publicDispatcherServlet(){super();}Overridepublicvoidinit(ServletConfigconfig)throwsServletException{super.init(config);// 获取在contextloadlistener中初始化的父容器this.parentApplicationContext(WebApplicationContext)this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);// ...// 创建controller的子容器this.webApplicationContextnewAnnotationConfigWebApplicationContext(sContextConfigLocation,this.parentApplicationContext);// ...}}既然引入了父子容器那么我们最重要的容器类DefaultListableBeanFactory也要支持了增加方法设置父容器// com.hc.minispring.ioc.four_beanfactory_and_event.beans.factory.support.DefaultListableBeanFactorypublicclassDefaultListableBeanFactoryextendsAbstractAutowireCapableBeanFactoryimplementsConfigurableListableBeanFactory{OverridepublicvoidsetParent(ConfigurableListableBeanFactorybeanFactory){this.parentbeanFactory;}}获取bean也要尝试从父容器中获取了// com.hc.minispring.ioc.four_beanfactory_and_event.beans.factory.support.DefaultListableBeanFactoryOverridepublicObjectgetBean(StringbeanName)throwsBeansException{Objectresultsuper.getBean(beanName);// 如果当前ioc容器没有则尝试从父容器中查找if(resultnull){// result this.parentBeanFctory.getBean(beanName);resultthis.parent.getBean(beanName);}returnresult;}2拆解dispatcher servlet2.1处理请求当前dispatcher servlet处理请求的代码如下protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{StringsPathrequest.getServletPath();// ...try{Methodmethodthis.mappingMethods.get(sPath);objthis.mappingObjs.get(sPath);objResultmethod.invoke(obj);}catch(SecurityExceptione){// ...}response.getWriter().append(objResult.toString());}可以看到获取处理请求的方法以及处理方法的执行在这里都一股脑全做了这完全不符合单一职责的原则并且扩展性也很弱比如增加一种获取处理请求方法的方式。所以需要对这一块进行一番改造。对于根据请求获取具体请求方法的职责我们定义如下接口// 职责根据请求信息获取处理请求的方法方法对象controller中的某个方法publicinterfaceHandlerMapping{HandlerMethodgetHandler(HttpServletRequestrequest)throwsException;}对于处理请求方法执行的职责定义如下接口/** * 职责负责执行具体controller的方法 */publicinterfaceHandlerAdapter{voidhandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException;}对应的针对当前使用RequestMapping映射请求的场景分别定义具体实现类RequestMappingXxx:packagecom.hc.minispring.web.v4_split_dispatcher;// .../** * 基于RequestMapping注解的url映射类 */publicclassRequestMappingHandlerMappingimplementsHandlerMapping{WebApplicationContextwac;privatefinalMappingRegistrymappingRegistrynewMappingRegistry();// ...}packagecom.hc.minispring.web.v4_split_dispatcher;importjava.io.IOException;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importcom.hc.minispring.web.v3_ioc.WebApplicationContext;/** * 基于RequestMapping注解的具具体执行方法实现类 */publicclassRequestMappingHandlerAdapterimplementsHandlerAdapter{WebApplicationContextwac;// ...}另外对于映射信息的维护职责定义类/** * 职责维护request到处理请求方法 */publicclassMappingRegistry{privateListStringurlMappingNamesnewArrayList();privateMapString,ObjectmappingObjsnewHashMap();privateMapString,MethodmappingMethodsnewHashMap();// ...}另外修改请求入口方法doGet为service这样可以处理各种类型的请求对应的修改Dispatcherservletpackagecom.hc.minispring.web.v4_split_dispatcher;// .../** * Servlet implementation class DispatcherServlet */publicclassDispatcherServletextendsHttpServlet{// ...// 修改点使用新组件处理请求privateHandlerMappinghandlerMapping;privateHandlerAdapterhandlerAdapter;Overridepublicvoidinit(ServletConfigconfig)throwsServletException{// ...}protectedvoidRefresh(){initController();// 修改点初始化handlermapping和handleradapterinitHandlerMappings(this.webApplicationContext);initHandlerAdapters(this.webApplicationContext);// ...}// 修改点service作为servlet入口这样可以处理各种类型的请求Overrideprotectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse){request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.webApplicationContext);try{doDispatch(request,response);}catch(Exceptione){e.printStackTrace();}finally{}}protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{HttpServletRequestprocessedRequestrequest;HandlerMethodhandlerMethodnull;// 修改点使用新组件获取处理请求的方法handlerMethodthis.handlerMapping.getHandler(processedRequest);if(handlerMethodnull){return;}// 修改点使用新组件处理请求即调用目标方法HandlerAdapterhathis.handlerAdapter;ha.handle(processedRequest,response,handlerMethod);}}3测试web.xml:?xml version1.0 encodingUTF-8?web-appxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:webhttp://xmlns.jcp.org/xml/ns/javaeexsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsdidWebApp_IDcontext-paramparam-namecontextConfigLocation/param-name!-- param-valueapplicationContext.xml/param-value--param-valuemvc_split_dispatcher/applicationContext.xml/param-value/context-paramlistenerlistener-classcom.hc.minispring.web.v3_ioc.ContextLoaderListener/listener-class/listenerservletservlet-nameminisMVC/servlet-nameservlet-classcom.hc.minispring.web.v4_split_dispatcher.DispatcherServlet/servlet-classinit-paramparam-namecontextConfigLocation/param-nameparam-value/WEB-INF/minisMVC-servlet.xml/param-value/init-paramload-on-startup1/load-on-startup/servletservlet-mappingservlet-nameminisMVC/servlet-nameurl-pattern//url-pattern/servlet-mapping/web-appioc配置文件applicationContext.xml:?xml version1.0 encodingUTF-8?beansbeanidaserviceclasscom.hc.minispring.web.v4_split_dispatcher.test.AServiceImpl//beansservelt配置文件minisMVC-servlet.xml?xml version1.0 encodingUTF-8 ?components!-- component-scan base-packagecom.hc.minispring.web.v2.test /--component-scanbase-packagecom.hc.minispring.web.v4_split_dispatcher.controller//componentscontrollerpublicclassHelloController{AutowiredprivateAServiceaservice;RequestMapping(/hello1527)publicStringdoTest(){returnaservice.sayHello();}}启动测试写在后面参考文章列表手把手带你写一个 MiniSpring 。