Spring MVC源碼分析
從以下三個方面進行介紹:
- Servlet與Spring MVC之間的關系
- Servlet框架線程是否安全
- Spring MVC是如何完全無web.xml啟動的
Spring MVC是基于Servlet實現的封裝。
首先回顧下Servlet:
Servlet是sun公司提供的一門用于開發動態web資源的技術。
Sun公司在其API中提供了一個servlet接口,用戶若想用發一個動態web資源(即開發一個Java程序向瀏覽器輸出數據),需要完成以下2個步驟:
1、編寫一個Java類,實現servlet接口。
2、把開發好的Java類部署到web服務器中。
按照一種約定俗成的稱呼習慣,通常我們也把實現了servlet接口的java程序,稱之為Servlet
創建工程:
IDEA添加如下參數可以防止長時間Build

需要Servlet環境,則進入Servlet的Jar包,兩種方式:
1.Tomcat自帶的
2.mavne 引入的
在JavaEE項目必須有web.xml,那么為啥在SpringBoot不需要web.xml?
1.xml版本:
public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("hello world"); } }
xml配置:
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.toov5.servlet01.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
啟動并且訪問:

注: Servlet線程不安全,單例才會產生共享。使用適合加鎖哦
關于過濾器和攔截器:
攔截器與過濾器區別
- 攔截器和過濾器都是基于Aop實現,能夠對請求執行之前和之后實現攔截。
- 過濾器是基于Servlet容器實現,對Web請求之前和之后實現攔截
- 攔截器不需要依賴于Servlet、不僅可以實現Web請求還有其他方法攔截等。
SpringMVC攔截器的使用
- 自定義攔截攔截請求Token
preHandle在業務處理器處理請求之前被調用;
postHandle在業務處理器處理請求執行完成后,生成視圖之前執行;
afterCompletion在DispatcherServlet完全處理完請求后被調用,可用于清理資源等 。afterCompletion()執行完成后開始渲染頁面
攔截器:
/** * 攔截傳遞參數中是否有token */ public class TokenInterceptor implements HandlerInterceptor { /** * 請求方法前置攔截,如果返回True表示會執行目標方法(請求方法) 如果返回false的情況下,則不會執行目標方法 * @param request * @param response * @param handler * @return * @throws Exception */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(">>>preHandle<<<"); //回去token String token = request.getParameter("token"); if (StringUtils.isEmpty(token)) { //響應下 response.getWriter().print("not find token"); return false; } return true; } /** * * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println(">>>>>postHandle<<<<<<<<<"); }
//渲染頁面之后執行 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println(">>>afterCompletion<<<"); } }
配置:
@Configuration @ComponentScan( basePackages = {"com.toov5.controller","com.toov5.service"}) @EnableWebMvc //等于開啟Spring MVC注解方式 @EnableAsync public class SpringMVCConfig implements WebMvcConfigurer { /** * 視圖解析器 * @return */ @Bean public InternalResourceViewResolver internalResourceViewResolver(){ InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver(); internalResourceViewResolver.setPrefix("/WEB-INF/view/"); internalResourceViewResolver.setSuffix(".jsp"); return internalResourceViewResolver; } //1. 手動注入攔截器到Spring中 @Bean public TokenInterceptor tokenInterceptor(){ return new TokenInterceptor(); } //2. 添加攔截器 public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(tokenInterceptor()).addPathPatterns("/**"); // /**表示攔截所有請求 也可以排除某個請求 } DispatcherServlet }
注意:使用攔截器一定要關閉EnableWebMvc 否則攔截器不會生效。
ServletContainerInitializer
關于Servlet的接口:ServletContainerInitializer. 涉及到Spring Boot Spring MVC如何實現沒有web.xml啟動的。
在web容器啟動時為提供給第三方組件機會做一些初始化的工作,例如注冊servlet或者filtes等,servlet規范中通過ServletContainerInitializer實現此功能。
每個框架要使用ServletContainerInitializer就必須在對應的jar包的META-INF/services 目錄創建一個名為javax.servlet.ServletContainerInitializer的文件,文件內容指定具體的ServletContainerInitializer實現類。
Servlet容器在初始化時候可以加載一些第三方相關依賴初始化工作,比如
實現接口:
@HandlesTypes(value = MyHandlesType.class) public class MyServletContainerInitializer implements ServletContainerInitializer { /** * 作用是servlet容器初始化加載一些操作 比如第三方依賴信息 手動加載Servlet、監聽器、過濾器 * @param set 獲取繼承該類MyHandersType類所有子類class信息 (官方稱之為感興趣的類) * @param servletContext * @throws ServletException */ public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException { // 1.打印所有感興趣的類型 for (Class<?> c : set) { System.out.println(c); } // 2.servletContext 手動注冊過濾器、servlet、監聽器 ServletRegistration.Dynamic payServlet = servletContext.addServlet("payServlet", new PayServlet()); payServlet.addMapping("/pay"); } }
定義類:
public class MyHandlesType { }
繼承類:
public class BookServlet extends MyHandlesType { }
定義servlet:
public class PayServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().print("this is pay"); } }
啟動并訪問
注: tomcat回去META-INF下面讀取配置:
tomcat啟動時候:


下面搭建Spring mvc的環境:
可以看到引入包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.1.RELEASE</version> </dependency>
后

DispatcherServlet是Spring MVC的核心類,客戶端所有的請求都轉發到DispatcherServlet,最終執行請求定義的方法。其實就是一個Servlet類,無非就是包裝來根據URL能夠映射找到我們Spring mvc中定義的方法。
源代碼分析:

看繼承圖:

繼承FrameworkServlet 繼承 HttpServlet
面向對象思想,重寫。執行先父類再之類。 執行父類的原因:
super.service(request, response);
請求過來先走Service方法,判斷類型 如果是get,執行doGet方法。
流程:HttpServlet Service 判斷請求如果Get請求
- getHandler(),通過url路徑地址查詢到具體的控制請求的方法,如果沒有找到情況下直接返回404。
Handler 對應的其實就是我們的控制層類方法
SpringMVC容器 存放當前jvm中所有url映射的路徑對應的請求的方法存放到Map集合。
Key:url value:請求方法
SpringMVC映射路徑的容器在什么時候被創建呢?
Servlet在調用我們的init的方法被創建的。
Handler請求控制層 HandlerMethod 指的請求具體方法。
Spring mvc中核心類:
dispatcherServlet 前端控制器,就是個Servlet類,包裝了而已,根據UTL能夠映射找到我們的Spring mvc定義的請求方法。
在上面的config 也配合了這個類。
關系:DispatcherServlet繼承FrameworkServlet繼承HttpServlet
流程執行關系:
HttpServlet service方法 判斷請求方法的類型
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); long lastModified; if (method.equals("GET")) { lastModified = this.getLastModified(req); if (lastModified == -1L) { this.doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader("If-Modified-Since"); } catch (IllegalArgumentException var9) { ifModifiedSince = -1L; } if (ifModifiedSince < lastModified / 1000L * 1000L) { this.maybeSetLastModified(resp, lastModified); this.doGet(req, resp); } else { resp.setStatus(304); } } } else if (method.equals("HEAD")) { lastModified = this.getLastModified(req); this.maybeSetLastModified(resp, lastModified); this.doHead(req, resp); } else if (method.equals("POST")) { this.doPost(req, resp); } else if (method.equals("PUT")) { this.doPut(req, resp); } else if (method.equals("DELETE")) { this.doDelete(req, resp); } else if (method.equals("OPTIONS")) { this.doOptions(req, resp); } else if (method.equals("TRACE")) { this.doTrace(req, resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[]{method}; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(501, errMsg); } }
FrameworkServlet doGet
DispatcherServlet doService 可以直接打斷點到這里
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { this.logRequest(request); Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap(); Enumeration attrNames = request.getAttributeNames(); label95: while(true) { String attrName; do { if (!attrNames.hasMoreElements()) { break label95; } attrName = (String)attrNames.nextElement(); } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet")); attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource()); if (this.flashMapManager != null) { FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } try { this.doDispatch(request, response); //核心方法! } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) { this.restoreAttributesAfterInclude(request, attributesSnapshot); } } }
看下
doDispatch:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null; Object dispatchException = null; try { processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request;
//獲取到Handler mappedHandler = this.getHandler(processedRequest); if (mappedHandler == null) { this.noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } // 執行攔截器的前置方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 執行請求的目標方法,獲取到 modelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, mv);
//執行攔截器的后置方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler dispatch failed", var21); } this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); } catch (Exception var22) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22); } catch (Throwable var23) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23)); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if (multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } }
關于 getHandler
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { Iterator var2 = this.handlerMappings.iterator(); while(var2.hasNext()) { HandlerMapping mapping = (HandlerMapping)var2.next(); HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
重點:
Iterator var2 = this.handlerMappings.iterator();
可以打個斷點看看:


handler請求控制層
handlerMethod 請求具體方法
handlerMapping 當前所有url路徑映射的集合,包括攔截器

有多個handler,表示來源,有xml方式的,有注解方式的,也有類中配置的。

然后獲取適配器: (可以自定義)
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { Iterator var2 = this.handlerAdapters.iterator(); while(var2.hasNext()) { HandlerAdapter adapter = (HandlerAdapter)var2.next(); if (adapter.supports(handler)) {
//返回這個適配器 return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
通過適配器,最終去執行方法。
DispatcherServlet源碼流程分析總結:
1.執行doDispatch
2.調用getHandler方法獲取請求目標的方法 也就是 請求url映射路徑對應的控制層具體的方法
handlerMappings的作用查找控制器位置,比如xml和注解方式。
3.調用getHandlerAdapter獲取控制層適配器 RequestMappingHandlerAdapter
4.執行攔截器前置方法 preHandle() 如果返回為true的話
5.執行實際請求目標方法 返回modeAndView對象
6.執行攔截器PostHandle()方法
7.設置渲染視圖層內容
8.執行攔截器afterCompletion方法
(29-05)

SpringMVC控制層容器初始化
- HttpServletBean init ()方法
- FrameworkServlet initServletBean方法→ initWebApplicationContext();
- DispatcherServlet onRefresh方法→ initStrategies()方法
DispatcherServlet:
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); //初始化上傳文件解析器(或者是多部分請求解析器) initLocaleResolver(context);//初始化本地化解析器 initThemeResolver(context);//初始化主題解析器 initHandlerMappings(context);//初始化處理器映射器 initHandlerAdapters(context);//初始化處理器適配器 initHandlerExceptionResolvers(context);//初始化處理器異常解析器 initRequestToViewNameTranslator(context);//初始化請求到視圖名翻譯器 initViewResolvers(context);//初始化視圖解析器 initFlashMapManager(context);//初始化重定向數據管理器 }
經過此處的調用:
protected void onRefresh(ApplicationContext context) { this.initStrategies(context); }
在父類
FrameworkServlet 進行調用
if (!this.refreshEventReceived) { Object var6 = this.onRefreshMonitor; synchronized(this.onRefreshMonitor) { this.onRefresh(wac); } }
一直往上找:
HttpServletBeand 的
init()方法
當servlet容器初始化時候進行初始化。
http://www.rzrgm.cn/yanghongfei/p/8507632.html
應用:
b
pom引用純Servlet:
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.0</version> </dependency> </dependencies>
注解的封裝:
掃包:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented public @interface ComponentScan { String value() default ""; }
@Controller注解:配合Config類
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Controller { String value() default ""; }
@Requesting注解:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestMapping { String value() default ""; }
config類:
@ComponentScan("com.test.controller")
public class SpringMvcConfig {
}
controller類:
@Controller public class PayController { @RequestMapping("/pay") public String pay() { return "pay"; } }
核心部分:

public class HttpServletBean extends HttpServlet { //HttpServletBean 作用 /** * SpringMVC思路: * 控制層和url映射關聯定義好存放到Map集合中 肯定在項目啟動時候 * 1.掃包獲取class中的方法有加上RequestMapping 如果有有該注解的話 存放到map集合 * 2.key:url:value 方法 * <p> * 訪問這個請求 根據url查找對應的執行的方法在通過java反射執行該方法。 */ @Override public void init() throws ServletException { // 初始化我們的springmvcbean的對象 和url與方法關聯 initServletBean(); } protected void initServletBean() { } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) { doService(req,resp); } protected void doService(HttpServletRequest req, HttpServletResponse resp) { } }
public class FrameworkServlet extends HttpServletBean { @Override protected void initServletBean() { onRefresh(); } protected void onRefresh() { } @Override protected void doService(HttpServletRequest req, HttpServletResponse resp) { } }
public class DispatcherServlet extends FrameworkServlet { private RequestMappingHandlerMapping requestMappingHandlerMapping; public DispatcherServlet() { requestMappingHandlerMapping = new RequestMappingHandlerMapping(); } @Override protected void onRefresh() { initStrategies(); } private void initStrategies() { requestMappingHandlerMapping.initHandlerMappings(); } @Override protected void doService(HttpServletRequest req, HttpServletResponse resp) { doDispatch(req, resp); } private void doDispatch(HttpServletRequest req, HttpServletResponse resp) { try { // 1.處理請求url String requestURI = req.getRequestURI(); // 2.根據url查找對應的Handler HandlerExecutionChain handler = getHandler(requestURI); if (handler == null) { noHandlerFound(req, resp); return; } // 3.使用java的反射機制執行請求方法 返回對應的modelAndView ModelAndView modelAndView = handler.handler(); // 4.開始渲染視圖層 render(modelAndView, req, resp); } catch (Exception e) { } } public void render(ModelAndView modelAndView, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String viewName = modelAndView.getViewName(); req.getRequestDispatcher("/WEB-INF/view/" + viewName + ".jsp").forward(req, resp); } private HandlerExecutionChain getHandler(String url) { HandlerMethod handlerMethod = requestMappingHandlerMapping.getHandlerMethod(url); if (handlerMethod == null) { return null; } HandlerExecutionChain handlerExecutionChain = new HandlerExecutionChain(handlerMethod); return handlerExecutionChain; } protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception { throw new Exception("沒有查找到對應的請求"); } }
接口
public interface WebApplicationInitializer { void onStartup(ServletContext servletContext) throws ServletException; }
實現:
public class AbstractDispatcherServletInitializer implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException { // 1.開始注冊我們的DispatcherServlet ServletRegistration.Dynamic dispatcherServlet = servletContext.addServlet("dispatcherServlet", new DispatcherServlet()); dispatcherServlet.addMapping("/");// 攔截所有的請求 // dispatcherServlet.setLoadOnStartup(1); } }
裝配類:
@HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { /** * onStartup servlet容器初始化的時候就會調用該方法 * * @param classInfos 獲取 WebApplicationInitializer 所有的子類 * @param ctx * @throws ServletException */ public void onStartup(Set<Class<?>> classInfos, ServletContext ctx) throws ServletException { for (Class<?> classInfo : classInfos) { //classInfo 都是WebApplicationInitializer類的子類 try { Method method = classInfo.getMethod("onStartup", ServletContext.class); Object object = classInfo.newInstance(); method.invoke(object, ctx); } catch (Exception e) { e.printStackTrace(); } } } }
反射工具類:
public class ReflexUtils { /** * 從包package中獲取所有的Class * * @param pack * @return */ public static Set<Class<?>> getClasses(String pack) { // 第一個class類的集合 Set<Class<?>> classes = new LinkedHashSet<Class<?>>(); // 是否循環迭代 boolean recursive = true; // 獲取包的名字 并進行替換 String packageName = pack; String packageDirName = packageName.replace('.', '/'); // 定義一個枚舉的集合 并進行循環來處理這個目錄下的things Enumeration<URL> dirs; try { dirs = Thread.currentThread().getContextClassLoader().getResources( packageDirName); // 循環迭代下去 while (dirs.hasMoreElements()) { // 獲取下一個元素 URL url = dirs.nextElement(); // 得到協議的名稱 String protocol = url.getProtocol(); // 如果是以文件的形式保存在服務器上 if ("file".equals(protocol)) { System.err.println("file類型的掃描"); // 獲取包的物理路徑 String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); // 以文件的方式掃描整個包下的文件 并添加到集合中 findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes); } else if ("jar".equals(protocol)) { // 如果是jar包文件 // 定義一個JarFile System.err.println("jar類型的掃描"); JarFile jar; try { // 獲取jar jar = ((JarURLConnection) url.openConnection()) .getJarFile(); // 從此jar包 得到一個枚舉類 Enumeration<JarEntry> entries = jar.entries(); // 同樣的進行循環迭代 while (entries.hasMoreElements()) { // 獲取jar里的一個實體 可以是目錄 和一些jar包里的其他文件 如META-INF等文件 JarEntry entry = entries.nextElement(); String name = entry.getName(); // 如果是以/開頭的 if (name.charAt(0) == '/') { // 獲取后面的字符串 name = name.substring(1); } // 如果前半部分和定義的包名相同 if (name.startsWith(packageDirName)) { int idx = name.lastIndexOf('/'); // 如果以"/"結尾 是一個包 if (idx != -1) { // 獲取包名 把"/"替換成"." packageName = name.substring(0, idx) .replace('/', '.'); } // 如果可以迭代下去 并且是一個包 if ((idx != -1) || recursive) { // 如果是一個.class文件 而且不是目錄 if (name.endsWith(".class") && !entry.isDirectory()) { // 去掉后面的".class" 獲取真正的類名 String className = name.substring( packageName.length() + 1, name .length() - 6); try { // 添加到classes classes.add(Class .forName(packageName + '.' + className)); } catch (ClassNotFoundException e) { // log // .error("添加用戶自定義視圖類錯誤 找不到此類的.class文件"); e.printStackTrace(); } } } } } } catch (IOException e) { // log.error("在掃描用戶定義視圖時從jar包獲取文件出錯"); e.printStackTrace(); } } } } catch (IOException e) { e.printStackTrace(); } return classes; } /** * 以文件的形式來獲取包下的所有Class * * @param packageName * @param packagePath * @param recursive * @param classes */ public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) { // 獲取此包的目錄 建立一個File File dir = new File(packagePath); // 如果不存在或者 也不是目錄就直接返回 if (!dir.exists() || !dir.isDirectory()) { // log.warn("用戶定義包名 " + packageName + " 下沒有任何文件"); return; } // 如果存在 就獲取包下的所有文件 包括目錄 File[] dirfiles = dir.listFiles(new FileFilter() { // 自定義過濾規則 如果可以循環(包含子目錄) 或則是以.class結尾的文件(編譯好的java類文件) public boolean accept(File file) { return (recursive && file.isDirectory()) || (file.getName().endsWith(".class")); } }); // 循環所有文件 for (File file : dirfiles) { // 如果是目錄 則繼續掃描 if (file.isDirectory()) { findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes); } else { // 如果是java類文件 去掉后面的.class 只留下類名 String className = file.getName().substring(0, file.getName().length() - 6); try { // 添加到集合中去 //classes.add(Class.forName(packageName + '.' + className)); //這里用forName有一些不好,會觸發static方法,沒有使用classLoader的load干凈 classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className)); } catch (ClassNotFoundException e) { // log.error("添加用戶自定義視圖類錯誤 找不到此類的.class文件"); e.printStackTrace(); } } } } }
ModelAndView:
public class ModelAndView { // 跳轉頁面名稱 private String viewName; public ModelAndView(String viewName) { this.viewName = viewName; } public String getViewName() { return viewName; } }
Handler: (handler有攔截器進行包裝,每個請求的方法有攔截器)
public class HandlerExecutionChain { HandlerMethod handlerMethod; // 攔截器 public HandlerExecutionChain(HandlerMethod handlerMethod) { this.handlerMethod = handlerMethod; } public ModelAndView handler() throws InvocationTargetException, IllegalAccessException { // 1. 使用java的反射機制執行我們請求方法 Method method = handlerMethod.getMethod(); Object bean = handlerMethod.getBean(); // 2.執行我們的請求的方法 Object viewName = method.invoke(bean, null); ModelAndView modelAndView = new ModelAndView((String) viewName); return modelAndView; } }
public class HandlerMethod { // 請求方法對應的bean對象 private Object bean; private Method method; public HandlerMethod(Object bean, Method method) { this.bean = bean; this.method = method; } public Object getBean() { return bean; } public Method getMethod() { return method; } /** * 1.參數的問題 */ }

com.mayikt.servlet.web.SpringServletContainerInitializer
JSP:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> successful! go on! </body> </html>
訪問:

關于適配器:
定義:將一個系統的接口轉換成另外一種形式,從而使原來不能直接調用的接口變得可以調用。
應用場景:
- Mybatis多種日志框架的整合
- SpringMVC適配器模式,Spring MVC通過Handler獲取對應的適配器,然后通過適配器執行我們請求的方法。
- 新老版本的兼容問題
Spring MVC中有三種適配器:
流程:
1.使用getHandlerAdapter獲取對應的hanlder的具體HandlerAdapter
2.HandlerAdapter接口有如下的子 c處理請求適配器(三種)
2.1繼承Controller方式所使用的適配器:SimpleControllerHandlerAdapter
2.2 HTTP請求處理器適配器:HttpRequestHandlerAdapter
3.3注解方式(@Controller)的處理器適配器:RequestMappingHandlerAdapter
使用適配器針對不同的handelr類型中安多不同的適配器實現執行。可以方便擴展。
適配器接口:
public interface HandlerAdapter { /** * 根據hanlder判斷是那個HandlerAdapter類型 如果找到對應的類型話返回true * * @param handler * @return */ boolean supports(Object handler); /** * 執行我們的請求方法 */ void handle(Object handler); }
適配器實現類:
public class AnnotationHandlerAdapter implements HandlerAdapter { /** * 注解形式的適配器 * * @param handler * @return */ public boolean supports(Object handler) { return (handler instanceof AnnotationController); } public void handle(Object handler) { ((AnnotationController) handler).hanlder(); } }
public class HttpRequestHandlerAdapter implements HandlerAdapter { /** * Http類型 適配器 * * @param handler * @return */ public boolean supports(Object handler) { return (handler instanceof HttpController); } public void handle(Object handler) { ((HttpController) handler).hanlder(); } }
接口:
public interface Controller { void hanlder(); }
不同的實現類:
public class HttpController implements Controller { public void hanlder() { System.out.println("HttpController"); } }
public class AnnotationController implements Controller { public void hanlder() { System.out.println("AnnotationController"); } }
Servlet 測試:
public class DispatcherServlet { private List<HandlerAdapter> handlerAdapters; public DispatcherServlet() { handlerAdapters = new ArrayList<HandlerAdapter>(); handlerAdapters.add(new HttpRequestHandlerAdapter()); handlerAdapters.add(new AnnotationHandlerAdapter()); } public void dispatcher() { // 1. 已經獲取到hanlder AnnotationController hanlder = new AnnotationController(); // 2.獲取具體適配器 HandlerAdapter handlerAdapter = getHandlerAdapter(hanlder); // 3.執行我們的請求方案 handlerAdapter.handle(hanlder); } public HandlerAdapter getHandlerAdapter(Controller controller) { if (this.handlerAdapters != null) { for (HandlerAdapter ha : this.handlerAdapters) { if (ha.supports(controller)) { return ha; } } } return null; } public static void main(String[] args) { new DispatcherServlet().dispatcher(); } }

浙公網安備 33010602011771號