模拟SpringMvc的实现(一)
SpringMvc是一个很优秀的框架,做web开发的基本都会用到。它整个框架的本质其实就是一个servlet。关于mvc的整体介绍可以参考我之前的另一篇博客http://blog.csdn.net/z344310362/article/details/51387724准备环境需要servlet3.0以上的依赖包。web容器需要需用支持servlet3.0的(如tomcat7以上)技术路线
SpringMvc是一个很优秀的框架,做web开发的基本都会用到。它整个框架的本质其实就是一个servlet。
关于mvc的整体介绍可以参考我之前的另一篇博客
http://blog.csdn.net/z344310362/article/details/51387724
准备环境
需要servlet3.0以上的依赖包。
web容器需要需用支持servlet3.0的(如tomcat7以上)
技术路线
- servlet
mvc的本质是一个servlet,放到mvc的框架里面,核心就是一个DispatcherServlet类。
这个类的继承关系如下:
DispatcherServlet->FrameworkServlet->HttpServlet->HttpServlet
从最后的一个HttpServlet中我们可以看到,虽然它层层隐藏,但是最终就是一个servlet。 mvc核心业务
mvc的核心业务就是servlet的核心,它主要就是:- 初始化业务:init()->initStrategies()
在初始化中mvc主要是在initStrategies()
这个方法里面完成了9个核心组件的注册。 - 请求处理:service()->doDispatch()
在处理请求中mvc的入口是在doDispatch()
方法里面的。这个方法中主要是根据请求匹配到对应的handler,进行具体的业务处理。
- 初始化业务:init()->initStrategies()
servlet注册
在这个demo中我们用到了servlet3.0以上才有的一个接口ServletContainerInitializer
继承了这个接口后我们容器启动后会调用这个接口里面提供的onStartup
方法。这样我们的一些初始化动作就可以在里面完成,包括servlet的动态注册。
我们的DispatcherServlet也就可以在里面注册了(以前注册一个servlet我们是在web.xml里面配置的),在这个demo中我们可以摒弃掉web.xml。
具体实现
结构预览
目前只是实现了一个大体的结构,所以很简单。红色矩形的2个类就是这个demo的核心类。MyContainerInitializer介绍
@HandlesTypes({WebApplicationInitializer.class}) public class MyContainerInitializer implements ServletContainerInitializer { @Override public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { System.out.println("MyContainerInitializer start"); LinkedList initializers = new LinkedList(); Iterator var4; if(webAppInitializerClasses != null) { var4 = webAppInitializerClasses.iterator(); while(var4.hasNext()) { Class initializer = (Class)var4.next(); if(!initializer.isInterface() && !Modifier.isAbstract(initializer.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(initializer)) { try { initializers.add((WebApplicationInitializer)initializer.newInstance()); } catch (Throwable var7) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7); } } } if(initializers.isEmpty()) { servletContext.log("No WebApplicationInitializer types detected on classpath"); } else { servletContext.log(initializers.size() + "WebApplicationInitializers detected on classpath"); var4 = initializers.iterator(); while(var4.hasNext()) { WebApplicationInitializer initializer1 = (WebApplicationInitializer)var4.next(); initializer1.onStartup(servletContext); } } } } }
这个类实现了ServletContainerInitializer这个接口,所以容器在启动时会调用里面的
onStartup
方法。
类声明的上面有一个@HandlesTypes({WebApplicationInitializer.class})
它标明了WebApplicationInitializer这个类的子类在启动时会添加到onStartup
方法里面的一个参数Set<Class<?>> webAppInitializerClasses
里面。这样我们通过这个参数就可以对这些类进行调用。public interface WebApplicationInitializer { void onStartup(ServletContext var1) throws ServletException; }
DispatcherServletInitializer介绍
这个类的主要用途是将DispatcherServlet动态注册到我们的容器里面。public class DispatcherServletInitializer implements WebApplicationInitializer{ public static final String DEFAULT_SERVLET_NAME = "dispatcher"; @Override public void onStartup(ServletContext var1) throws ServletException { this.registerDispatcherServlet(var1); } protected void registerDispatcherServlet(ServletContext servletContext) { ServletRegistration.Dynamic registration = servletContext.addServlet(DEFAULT_SERVLET_NAME, new DispatcherServlet()); registration.setLoadOnStartup(1); registration.addMapping("*.do"); } }
这个类实现了
WebApplicationInitializer
这个接口,所以它在启动的时候会被添加到2中的MyContainerInitializer
里面的onstartup里面。Set<Class<?>>
这个类里面用到了ServletRegistration.Dynamic
来动态注册servlet。DispatcherServlet介绍
看似复杂的springmvc被剥光后就剩下一个DispatcherServlet类。/** * @Author:zhourj * @Description: * @Date Create in 12:01 2016/11/13 0013 */ public class DispatcherServlet extends FrameworkServlet { protected void onRefresh() { this.initStrategies(); } /** * 初始化MVC的9个组件 */ protected void initStrategies() { /*this.initMultipartResolver(context); this.initLocaleResolver(context); this.initThemeResolver(context); this.initHandlerMappings(context); this.initHandlerAdapters(context); this.initHandlerExceptionResolvers(context); this.initRequestToViewNameTranslator(context); this.initViewResolvers(context); this.initFlashMapManager(context);*/ } protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { this.doDispatch(request,response); } protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("mvc 分配请求"); PrintWriter writer = null; try { writer = response.getWriter(); // response.setContentLength(responseContent.length()); writer.write("mvc处理结果"); writer.flush(); writer.close(); } catch (Exception e) { } finally { if (writer != null) { writer.close(); } } } }
目前我基本没有实现这个类的什么方法,就是展示他的大体结构。
从3中的代码registration.addMapping("*.do");
我们知道这个servlet将所有”.do”的请求的包含给自己处理了。所有要让我们的mvc响应到的请求就必需以“.do”结尾。然后具体请求的分配就交给doDispatch
这个方法处理,它具体会利用HandlerMappings组件来帮忙寻找具体的handler。pom.xml
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>test</finalName> <resources> <resource> <directory>src/main/java</directory> <excludes> <exclude>**/*.java</exclude> </excludes> </resource> </resources> </build>
这里我只用到了servlet3.1的一个依赖。里面resource的配置是将根路径里面的配置文件拷贝到class里面。这里主要是我用IDEA的一个坑,没自动帮我拷贝进去。
这里需要注意到的要有这个META-INF,里面要有这个一个文件。这样启动的时候2中的MyContainerInitializer onstartup方法才能进去。这是servlet中规定的。
本文章主要是个人学习归纳
源代码下载:http://download.csdn.net/detail/z344310362/9694233
更多推荐
所有评论(0)