0 Резюме
В этой статье кратко объясняется ссылка на отображение процессора SpringMVC с уровня исходного кода, то есть подробный процесс поиска контроллера
1 процесс запроса SpringMVC
Контроллер ищет шаги с 1 по 2, соответствующие вышеуказанному изображению
Схема схемы SpringMVC подробная операция
2 процесс инициализации SpringMVC
2.1 Сначала понимайте две категории
1. requestmappingInfo
Аннотация запроса на инкапсуляцию
Содержит соответствующую информацию о заголовках HTTP -запросов
Экземпляр соответствует аннотации запросов
2.handlermethod
Метод обработки запросов на инкапсуляцию контроллера
Включает в себя объект бобов, к которому принадлежит метод, объект метода, соответствующий методу, параметры метода и т. Д.
RequestMappingHandlermapping Назначение
Во время инициализации SpringMVC
Сначала выполнить Awperporpertiesset of RequestMappingHandlermapping
Затем введите AbstracThandLermethodMapping Afterpropertiesset
Этот метод введет Inithandlermetods этого класса
Отвечает за сканирование бобов из ApplicationContext, а затем поиск и регистрация методов процессора из бобов
// Сканирование бобов в приложении Context, обнаружение и зарегистрированные методы обработчика. getApplicationContext (). getBeanNamesFortype (object.class)); // Передача массива BeanName для (String Beanname: Beannames) {// ishandler будет судить, содержит ли определение бобов аннотацию контроллера или аннотацию запроса на основе бобов. If (ishandler (getApplicationContext (). GetType (beanname))) {detecthandlermethods (beanname); }} handlermethodsinitialize (gethandlermethods ());} RequestMappingHandlermapping#ishandler
Приведенный выше метод должен определить, содержит ли текущее определение бобов аннотацию или аннотацию запроса на предмет запросов.
Если вступает в силу только запрос? Нет!
Потому что в этом случае класс не будет зарегистрирован как пружинный фасоль при инициализации пружины, а класс не будет проходить при прохождении имени Бенна
После подтверждения того, что фасоль является обработчиком, конкретный метод обработчика будет найден из фасоли (то есть метод обработки запросов, определенный в классе контроллера). Код поиска выглядит следующим образом
/** * Ищите методы обработчика в обработчике * @param обработчик имени боба обработчика или экземпляра обработчика */Защищенная void detecthandlermethods (окончательный обработчик объекта) {// Получить объект класса текущего контроллера Beanclass <?> Handlertype = (экземпляр string instanceof string)? GetApplicationContext (). GetType ((String) Handler): handler.getClass (); // Избегайте повторяющихся вызовов для getMappingFormethod, чтобы восстановить экземпляр requestMappingInfo final Map <Method, t> mappings = new IdentityHashmap <method, t> (); // То же, что и выше, это также объект класса окончательного класса контроллера <?> UserType = classutils.getUserclass (HandlerType); // Получить все методы обработчика текущего боба // Определите, имеет ли он набор запросов в соответствии с методом // Если есть, создать набор экземпляров requestMappingInfo <метод> methods = handlermethodector.selectmethods (usertype, new MethodFilter () {@Override public boolean matches (метод метод) {t mapping = getMappingFormethod (methodType -methodpe -methodpe) {t mapping = getmappormethod (methodpe) (if -methodpepplion! null) {mappings.put (method, maping); // Путешествие и зарегистрировать все метод обработчика текущего Bean для (метода метода: методы) {// Метод обработчика регистрации и введите следующий метод registerhandlermethod (обработчик, метод, mappings.get (method)); } В приведенном выше коде есть два места, которые вызывают getMappingFormethod
Создать requestMappingInfo с использованием аннотации запроса Method and Type rewertmapping
@Override Protected requestMappingInfo getMappingFormethod (метод метода, класс <?> HandlerType) {requestMappingInfo info = null; // Получить метод @Requestmapping requestMapping Methodannotation = annotationutils.findannotation (метод, requestmapping.class); if (methodannotation! = null) {requestCondition <?> MethodCondition = getCustomtomethodCondition (метод); info = createrequestmappingInfo (Methodannotation, Methodcondition); // Получить аннотацию @requtestmapping из бобов, к которому метод принадлежит запросу typeannotation = annotationutils.findannotation (HandlerType, requestMapping.class); if (typeannotation! = null) {requestCondition <?> typeCondition = getCustomTyPecondition (HandlerType); // слияние двух аннотаций @Requestmapping info = createrequestmappingInfo (typeannotation, typecondition) .combine (info); }} return info; } Цель этого метода состоит в том, чтобы создать объект requestMappingInfo на основе метода метода обработчика. Во -первых, определите, содержит ли Mehtod аннотацию запроса. Если это так, создайте объект requestMappingInfo непосредственно на основе содержания аннотации. После создания определите, содержит ли бобы, на который текущий метод также содержит аннотацию задания. Если эта аннотация включена, будет создан объект requestMappingInfo на основе аннотации в классе. Затем объект requestMappingInfo на методе слияния возвращается, и объединенный объект наконец возвращается. Теперь, оглядываясь на метод DeteCthandlerMethods, есть два вызова для метода GetMappingFormethod. Я лично думаю, что это может быть оптимизировано. Оценивая, является ли метод обработчиком в первую очередь, объект созданных запросов requestMappingInfo может быть сохранен и использован непосредственно позже, что означает, что процесс создания объекта requestMappingInfo отсутствует. Затем немедленно введите метод RegisterHandlerMehtod, следующим образом
Protected void RegisterhandLermethod (обработчик объекта, метод метода, t -отображение) {// Создание ручного хранта рук. Handlermethod oldhandlermethod = handlermethods.get (mapping); //Check whether there is ambiguity in the configuration if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) { throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() + "' bean method /n" + newHandlerMethod + "/nto " + mapping + ": There is already '" + OldHandlermethod.getbean () + "'Bean Method/n" + OldHandlerMethod + "mappen."); } this.handlermethods.put (mapping, newhandlermethod); if (logger.isinfoenabled ()) {logger.info ("mappen /" " + mapping +" /"на" + newhandlermethod); } // Получить значение аннотации @Requestmapping, а затем добавить запись отображения valueMappingInfo в набор urlmap <string> patterns = getMappathPathPattern (отображение); for (String Pattern: Patterns) {if (! getPathMatcher (). Ispattern (Pattern)) {this.urlmap.add (pattern, mapping); }}} Здесь тип t estistmappingInfo. Этот объект является соответствующей информацией аннотации запроса метода в соответствии с конкретным инкапсулированным контроллером. Аннотация запроса соответствует объекту requestMappingInfo. Handlermethod похож на requestmappingInfo и представляет собой инкапсуляцию конкретных методов обработки под контролем. Сначала посмотрите на первую строку метода и создайте объект Handlermethod на основе Handler и Mehthod. Вторая строка использует карту ручных рук, чтобы получить ручной работы, соответствующий текущему отображению. Затем определите, существует ли та же самая конфигурация запроса. Следующая конфигурация вызовет выброшенную здесь
Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map...
аномальный
@Controller @requestmapping ("/ammidourytest") открытый класс AmbiguousTestController {@RequestMapping (value = "/test1") @Responsebody public String test1 () {return "test1"; } @RequestMapping (value = "/test1") @Responsebody public String test2 () {return "Метод Test2"; }} Проверьте, является ли конфигурация запроса двусмысленности во время фазы запуска SpringMVC (инициализации), которая является одной из вещей, которые следует проверить на неоднозначность (место для проверки неоднозначности во время выполнения будет упомянуто позже). Затем, подтвердив, что конфигурация является нормальной, объекты requestmappingInfo и handlermethod будут добавлены в HandlerMetods (LinkedHashmap), а затем в URLMAP будут добавлены объекты reuqestmapingInfo.
Простая резюме метода регистрации
Есть три основные обязанности этого метода
1. Проверьте, является ли конфигурация аннотации запросов двусмысленностью.
2. Создайте карту requestMappingInfo для Handlermethod. Эта карта представляет собой переменную элемента ручной работы AbstracThandlerMethodMap. LinkedHashmap.
3. Создайте переменную элемента urlmap of AbstracThandlerMethodMapping и Multivaluemap. Эта структура данных может быть понята как карта>. Ключ типа строки хранит значение аннотации запроса на методе обработки. Это конкретный URI
Сначала есть следующий контроллер
@Controller @requestmapping ("/urlmap") открытый класс urlmapcontroller {@requestmapping (value = "/test1", method = requestMethod.get) @Responsebody public String test1 () {return "метод Test1"; } @RequestMapping (value = "/test1") @Responsebody public String test2 () {return "Метод Test2"; } @Requestmapping (value = "/test3") @Responsebody public String test3 () {return "Метод Test3"; }} После завершения инициализации структура URLMAP, соответствующая абстрактандлерметодмии, выглядит следующим образом
Выше всего является основным процессом инициализации SpringMVC
Процесс поиска
Чтобы понять процесс поиска, с вопросом, доступны следующие контроллеры
@Controller @requestmapping ("/supuptest") открытый класс LookuptestController {@RequestMapping (value = "/test1", method = requestMethod.get) @Responsebody public String test1 () {return "Метод Test1"; } @RequestMapping (value = "/test1", headers = "referer = https: //www.baidu.com") @Responsebody public String test2 () {return "Метод Test2"; } @RequestMapping (value = "/test1", params = "id = 1") @Responsebody public String test3 () {return "Метод Test3"; } @RequestMapping (value = "/*") @Responsebody public String test4 () {return "Метод Test4"; }} Есть запросы следующим образом
Какой метод введет этот запрос?
После получения запроса веб -контейнер (Tomcat, Jetty) передается DispatcherServlet для обработки. Frameworkservlet вызывает соответствующий метод запроса (например: получить вызовы Doget), а затем вызывает метод ProcessRequest. После входа в метод ProcessRequest после серии обработки введите метод до осервиса в строке: 936. Затем введите метод Dodispatch в Line856. Получите обработчик запрашиваемого процессора в настоящее время: 896. Затем введите метод исказовать abstracThandlerMethodMapping. Код выглядит следующим образом
Защищенный Handlermethod LookupUphandLermethod (String Lookuppath, httpservletrequest) Throws Exception {list <copt> matches = new ArrayList <Match> (); // Получить DirectPathMatches на основе List URI <T> DirectPathMatches = this.urlMap.get (LookUppath); if (DirectPathMatches! = null) {addMatchingMappings (DirectPathMatches, Matches, запрос); } // Не существует прямого сопоставления requestMappingInfo, итерации через все запросы mappingInfo if (matches.isempty ()) {// Нет выбора, кроме как пройти все сопоставления AddMatchingMappings (this.handlermethods.keyset (), совпадения, запрос); } // Получить ручной работы, соответствующую лучшему Match RequestMappingInfo if (! Matches.isempty ()) {Comporator <Tack> компаратор = новый MatchComparator (getMappingComparator (запрос)); Collections.sort (Matches, Comparator); if (logger.istraceenabled ()) {logger.trace ("найдено" + matches.size () + "Сопоставление (ы) для [" + lookuppath + "]:" + matches); } // Проверьте двусмысленность конфигурации снова совпадать с bestmatch = matches.get (0); if (matches.size ()> 1) {match secondbestmatch = matches.get (1); if (comparator.compare (bestmatch, secondbestmatch) == 0) {method m1 = bestmatch.handlermethod.getmethod (); Метод m2 = secondbestmatch.handlermethod.getmethod (); Бросьте новое allodalStateException («неоднозначные методы обработчика, отображенные для пути http '" + request.getRequesturl () + "': {" + m1 + "," + m2 + "}"); }} handlematch (bestmatch.mapping, lookuppath, request); return bestmatch.handlermethod; } else {return handlenomatch (handlermethods.keyset (), lookuppath, request); }} Введите метод Lookupuphandlermethod, где Lookuppath = "/lookuptest/test1", согласно Lookuppath, то есть запрашиваемый URI. Напрямую найдите URLMAP и получите список запросов, который соответствует напрямую. Здесь мы сопоставляем 3 requestMappingInfos. следующее
Затем введите метод AddMatchingMappings
Private void AddMatchingMappings (Collection <t> отображения, список <Tack> Matches, httpservletRequest) {for (t mapping: mappings) {t match = getMatchingMapping (отображение, запрос); if (match! = null) {matches.add (new Match (match, handlermethods.get (mapping))); }}} Ответственность этого метода состоит в том, чтобы быть пройденным, могут ли соответствовать текущий запрашиваемый URI и запрос MapingInfo в сопоставлении, и, если это так, создать тот же объект requestMappingInfo. Затем получите ручной работы, соответствующий запросу. Затем создайте объект соответствия и добавьте его в список совпадений. После выполнения метода addmatchingmappingsing вернитесь в поиск и по имени. В настоящее время у матчей все еще есть 3 объекта запроса, которые могут соответствовать. Следующий процесс состоит в том, чтобы сортировать список совпадений, а затем получить первый элемент списка в качестве лучшего совпадения. Возвращает ручное матч. Здесь мы вводим метод сравнения requestMappingInfo и рассмотрим конкретную логику сортировки. Код выглядит следующим образом
public int compareto (requestMappingInfo, httpservletrequest) {int result = patterscondition.compareto (другие.getPatternScondition (), request); if (result! = 0) {return result; } result = paramscondition.compareto (ore.getParamScondition (), запрос); if (result! = 0) {return result; } result = headersCondition.compareto (ore.getheaderscondition (), request); if (result! = 0) {return result; } result = consumerCondition.compareto (другие.getConsumErcondition (), запрос); if (result! = 0) {return result; } result = presemingESCONDITION.comPareto (другие.getProducescondition (), запрос); if (result! = 0) {return result; } result = methodScondition.compareto (ore.getMethodScondition (), запрос); if (result! = 0) {return result; } result = CustomConditionholder.comPareto (другие.customConditionholder, запрос); if (result! = 0) {return result; } return 0;} Как вы можете видеть в коде, порядок совпадений является значением> Params> заголовки> Поглощает> производить> методы> пользовательские. Видя это, на предыдущий вопрос можно легко ответить. В случае того же значения, параметры могут сначала соответствовать. Таким образом, этот запрос введет метод test3 (). Вернитесь к поиску и найдите ручной работы. SpringMVC снова проверит неоднозначность конфигурации здесь. Принцип проверки здесь состоит в том, чтобы сравнить два запроса MapingInfos с высшей степенью соответствующей степени. Здесь могут быть вопросы, которые при инициализации SpringMVC существует неоднозначная проверка конфигурации, почему она снова проверяется здесь? Если сейчас в контроллере есть два метода, можно проверить следующую конфигурацию с помощью неоднозначности инициализации.
@Cheardmethod.get, requestmethod.post})@respensbodypublic string test5 (return.get, reoubtmethod.stest string test, reousbody string test, rectomedy string test, rectomedy test, rectomedy test5 test, rectomedy test, rectomedy test, rectomedy test, rectomedy test, rectomedy test, rectomedy test, rectomedy test, reoutmethod. stectmod. stectmod.
Теперь выполните запрос http: // localhost: 8080/springmvc-demo/lookuptest/test5, и он будет брошен в метод Lookuphandlermethod
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/SpringMVC-Demo/LookupTest/test5' исключение. Исключение брошено здесь, потому что метод сравнения requestmethodsrequestcondition является номером метода сравнения. Код выглядит следующим образом
public int compareto (requestmethodsrequestcondition Другое, httpservletrequest) {return other.methods.size () - this.methods.size ();}Когда совпадает подстановочный знак? Когда requestMappingInfo, который непосредственно соответствует значению, не может быть получен с помощью URLMAP, сопоставление подстановочных знаков будет использоваться для ввода метода AddMatchingMappingsings.
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.