本節咱們繼續分析HandlerMapping另外一個實現類BeanNameUrlHandlerMapping,從類的名字可知,該類會根據請求的url與spring容器中定義的bean的name屬性值進行匹配。前端
本系列文章是基於Spring5.0.5RELEASE。java
類的繼承關係,以下圖:git
紅框的類就是咱們本章要分析的類。github
與SimpleUrlHandlerMapping類圖對比,BeanNameUrlHandlerMapping類繼承自AbstractDetectingUrlHandlerMapping抽象類,其又繼承自AbstractUrlHandlerMapping抽象類,再往上繼承關係與SimpleUrlHandlerMapping一致。web
上一章咱們分析了SimpleUrlHandlerMapping的建立初始化過程,BeanNameUrlHandlerMapping的建立初始化過程與SimpleUrlHandlerMapping同樣,方法的入口在抽象類AbstractDetectingUrlHandlerMapping中的initApplicationContext()方法。調用原理參考http://www.javashuo.com/article/p-exqdlurm-kq.htmlspring
經過在應用程序上下文中對全部已定義的bean,檢測handler與URL的映射。主要代碼以下:segmentfault
// 初始化容器上下文時調用 @Override public void initApplicationContext() throws ApplicationContextException { // 調用父類AbstractHandlerMapping初始化攔截器,與SimpleUrlHandlerMapping同樣 super.initApplicationContext(); // 處理url和bean name,具體註冊調用父類AbstractUrlHandlerMapping類完成 detectHandlers(); } protected void detectHandlers() throws BeansException { // 獲取應用上下文 ApplicationContext applicationContext = obtainApplicationContext(); if (logger.isDebugEnabled()) { logger.debug("Looking for URL mappings in application context: " + applicationContext); } // 獲取上下文中定義的bean String[] beanNames = (this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) : applicationContext.getBeanNamesForType(Object.class)); // Take any bean name that we can determine URLs for. for (String beanName : beanNames) { // 經過模板方法模式調用BeanNameUrlHandlerMapping子類處理 String[] urls = determineUrlsForHandler(beanName); if (!ObjectUtils.isEmpty(urls)) { // 調用父類AbstractUrlHandlerMapping將url與handler存入map registerHandler(urls, beanName); } else { if (logger.isDebugEnabled()) { logger.debug("Rejected bean name '" + beanName + "': no URL paths identified"); } } } }
實現HandlerMapping接口,將url與handler bean進行映射,bean的name屬性需以"/"開頭,源碼以下:api
@Override protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList<>(); if (beanName.startsWith("/")) { urls.add(beanName); } String[] aliases = obtainApplicationContext().getAliases(beanName); for (String alias : aliases) { if (alias.startsWith("/")) { urls.add(alias); } } return StringUtils.toStringArray(urls); }
引入Spring MVC支持,代碼以下:spring-mvc
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>
新建spring MVC配置文件,代碼以下:mvc
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd" default-autowire="byName"> <!-- 配置HandlerMapping映射處理器 --> <bean id="beanNameUrlHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> </bean> <!-- 自定義Handler --> <bean id="/demo" class="com.github.dalianghe.controller.DemoController"/> </beans>
配置Spring MVC 前端控制器DispatcherServlet,代碼以下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>Archetype Created Web Application</display-name> <servlet> <!-- Servlet名稱,可任意定義,但必須與servlet-mapping中對應 --> <servlet-name>dispatcher</servlet-name> <!-- 指定Spring MVC核心控制類,即J2EE規範中的前端控制器(Front Controller) --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 指定Spring MVC配置文件,默認在WEB-INF目錄下,切名字爲[servlet-name]-servlet.xml,此文件中配置web相關內容,好比:指定掃描Controller路徑、配置邏輯視圖前綴後綴、上傳文件等等 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-servlet.xml</param-value> </init-param> <!-- 該參數控制是否使用自定義的HandlerMapping true 從Spring上下文環境中加載HandlerMapping類型的bean false 加載bean名稱爲handlerMapping的bean --> <init-param> <param-name>detectAllHandlerMappings</param-name> <param-value>false</param-value> </init-param> <!-- 此配置的值爲正整數時,表示容器啓動時初始化,即調用Servlet的init方法 --> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <!-- 定義servlet映射 --> <servlet-mapping> <!-- 與servlet中servlet-name對應 --> <servlet-name>dispatcher</servlet-name> <!-- 映射全部的url --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
編寫Controller控制器,代碼以下:
import org.springframework.lang.Nullable; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class DemoController implements Controller{ @Nullable @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { request.getServletContext().log("進入Controller(Handler)處理器。。。" + this); return null; } }
至此,代碼編寫完畢。
啓動程序,訪問地址http://localhost:8087/demo,在控制檯看到日誌信息,說明驗證成功。以下圖:
本文分析了BeanNameUrlHandlerMapping類,若是看過上篇文章就發現,SimpleUrlHandlerMapping與BeanNameUrlHandlerMapping都實現HandlerMapping接口,即處理url與handler的映射,只是處理的策略不一樣而已。
BeanNameUrlHanderlMapping有以下不足:
最後建立了qq羣方便你們交流,可掃描加入,同時也可加我qq:276420284,共同窗習、共同進步,謝謝!