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