<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Spring MVC源碼分析

       

      從以下三個方面進行介紹:

      1.  Servlet與Spring MVC之間的關系
      2.  Servlet框架線程是否安全
      3. 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攔截器的使用
      1. 自定義攔截攔截請求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請求

      1. 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控制層容器初始化
      1. HttpServletBean  init ()方法
      2. FrameworkServlet initServletBean方法→  initWebApplicationContext();
      3. 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>

       

      訪問:

       

       

       

      關于適配器:

      定義:將一個系統的接口轉換成另外一種形式,從而使原來不能直接調用的接口變得可以調用。

       

      應用場景:

      1. Mybatis多種日志框架的整合
      2. SpringMVC適配器模式,Spring MVC通過Handler獲取對應的適配器,然后通過適配器執行我們請求的方法。
      3. 新老版本的兼容問題

       

       

      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();
          }
      
      }

       

      posted @ 2019-11-17 00:50  toov5  閱讀(387)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 在线精品视频一区二区| 亚洲高潮喷水无码AV电影| 性男女做视频观看网站| 精品国产性色av网站| 亚洲国产精品久久久久秋霞| 欧美一级黄色影院| 高清精品一区二区三区| 亚洲欧洲av一区二区久久| 国产精品福利中文字幕| 无码人妻熟妇av又粗又大| 国产精品第一页中文字幕| 国产a级三级三级三级| av色蜜桃一区二区三区| 久久永久视频| 久久精品丝袜高跟鞋| 国产真人性做爰久久网站| 亚洲一线二线三线品牌精华液久久久 | 欧美性猛交xxxx免费看| 亚洲无av中文字幕在线| 男女做爰真人视频直播| 天干天干夜天干天天爽| 欧美一级黄色影院| 栾城县| 男人的天堂av一二三区| 全球成人中文在线| 午夜国产精品福利一二| 在线a人片免费观看| 国产亚洲人成网站观看| 顶级欧美熟妇xx| 国产精品久久人妻无码网站一区 | 久热综合在线亚洲精品| 婷婷四虎东京热无码群交双飞视频| 国产精品久久无码不卡黑寡妇| 精品国产一区二区三区香| 人妻av一区二区三区av免费| 国产精品日韩中文字幕| 久久久久亚洲精品无码系列| 日本一区二区精品色超碰| 国内精品免费久久久久电影院97| 国产成人精选视频在线观看不卡| 爱性久久久久久久久|