Специальное введение автомобиля
Этот специальный поезд представляет собой специальный поезд для анализа исходного кода обработки запросов Spring Boot. Он в основном используется для анализа того, как Spring Boot направляет наш запрос к указанному методу контроллера и вызывает выполнение.
проблема с машиной
Зачем мы добавляем метод в контроллер, аннотируем его аннотацией @RequestMapping, указываем путь, и его можно использовать для обработки веб-запроса?
Если пути запросов нескольких методов согласованы, как с этим справляется Spring Boot?
Пример личного автомобиля
@RestController
@RequestMapping("/persons")
public class PersonController {
private static List<Person> personList = new ArrayList<>();
static {
personList.add(new Person(10001, "test1"));
personList.add(new Person(10002, "test2"));
personList.add(new Person(10003, "test3"));
personList.add(new Person(10004, "test4"));
personList.add(new Person(10005, "test5"));
}
@GetMapping("/")
public List<Person> list() {
return personList;
}
@GetMapping("/{id}")
public Person get(@PathVariable("id") Integer id) {
Person defaultPerson = new Person(88888, "default");
return personList.stream().filter(person -> Objects.equals(person.getId(), id)).findFirst().orElse(defaultPerson);
}
@PostMapping("/")
public void add(@RequestBody Person person) {
personList.add(person);
}
@PutMapping("/")
public void update(@RequestBody Person person) {
personList.removeIf(p -> Objects.equals(p.getId(), person.getId()));
personList.add(person);
}
}
Пример кода предоставляет запросы GET, POST и PUT.Далее мы проанализируем исходный код на примере.
Специальный анализ автомобиля
Этот анализ в основном анализирует два основных аспекта: инициализацию запроса и обработку запроса.
инициализация запроса
процесс запроса
Завершенный процесс запроса представляет собой запрос ---> обработка ---> ответ, и обработка бизнес-логики, наконец, передается сервлету, который мы создали для обработки. Раньше при использовании среды Spring MVC мы настраивали DispathcherServlet в файле web.xml. Далее давайте взглянем на диаграмму классов DispathcherServlet.
На приведенном выше рисунке вы можете ясно увидеть отношения наследования DispatcherServlet. Один из классов с именем HttpServlet, если вы написали сервлет, должен быть знаком с ним.В прошлом, на основе разработки сервлета, будет создан класс реализации сервлета, он унаследует HttpServlet и перепишет метод службы, и, наконец, настроит тот, который мы созданный в web.xml.Класс реализации сервлета, чтобы мы могли использовать созданный класс реализации сервлета для обработки наших веб-запросов.
Инициализация HttpServlet
При первом запросе мы инициализируем сервлет, который в основном используется для инициализации ресурсов. Метод инициализации HttpServlet объявлен родительским классом GenericServlet и реализован подклассом HttpServletBean.
Метод инициализации: HttpServletBean#init
@Override
public final void init() throws ServletException {
// ...省略部分代码
// Let subclasses do whatever initialization they like.
// 暴露出去一个方法,可以让子类初始化一些自己想要初始化的内容
initServletBean();
}
Создать WebApplicationContext: FrameworkServlet#initServletBean
@Override
protected final void initServletBean() throws ServletException {
// ...省略部分代码
try {
// 初始化WebApplicationContext对象
this.webApplicationContext = initWebApplicationContext();
// 空实现
initFrameworkServlet();
}
// ...省略部分代码
}
Инициализируйте объект WebApplicationContext: FrameworkServlet#initWebApplicationContext.
protected WebApplicationContext initWebApplicationContext() {
// 获取WebApplicationContext对象
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// ... 省略部分代码
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
// 刷新资源
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
Обновить ресурсы: DispatcherServlet#onRefresh
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
Стратегия инициализации: DispatcherServlet#initStrategies
protected void initStrategies(ApplicationContext context) {
// 初始化多文件解析器
initMultipartResolver(context);
// 初始化本地化解析器
initLocaleResolver(context);
// 初始化主题解析器
initThemeResolver(context);
// 初始化HandlerMapping
initHandlerMappings(context);
// 初始化HandlerAdapter
initHandlerAdapters(context);
// 初始化异常解析器
initHandlerExceptionResolvers(context);
// 初始化请求到视图名称翻译器
initRequestToViewNameTranslator(context);
// 初始化视图解析器
initViewResolvers(context);
initFlashMapManager(context);
}
Давайте взглянем на реализацию HandlerMapping инициализации: DispatcherServlet#initHandlerMappings
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 从IOC容器中获取类型为HandlerMapping的bean
// 对应的bean有RequestMappingHandlerMapping、SimpleUrlHandlerMapping、WelcomePageHandlerMapping
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
// 对HandlerMapping进行排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
}
Анализируя реализацию инициализации HandlerMapping, можно сделать вывод, что все операции инициализации сводятся к получению соответствующего типа Bean из IOC-контейнера, а затем присвоению атрибутов.
Поскольку bean-компонент HandlerMapping можно получить из контейнера IOC, должно быть место для определения bean-компонента. Откройте класс WebMvcAutoConfiguration, вы увидите следующий код
/**
* Configuration equivalent to {@code @EnableWebMvc}.
* 此配置等同于使用@EnableWebMvc注解
*/
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory;
private final WebMvcRegistrations mvcRegistrations;
public EnableWebMvcConfiguration(
ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,
ListableBeanFactory beanFactory) {
this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
this.beanFactory = beanFactory;
}
// 声明RequestMappingHandlerAdapter bean
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
|| this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
// 声明RequestMappingHandlerMapping bean
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping();
}
}
Вы можете увидеть объявления компонентов HandlerAdapter и HandlerMapping в приведенном выше коде.
Создать RequestMappingHandlerMapping
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
// 创建RequestMappingHandlerMapping对象
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
// 设置属性
mapping.setOrder(0);
// 设置拦截器
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
// ...省略部分代码
return mapping;
}
Вы можете видеть, что помимо создания объекта RequestMappingHandlerMapping все остальное — это установка атрибутивной информации.Далее сосредоточьтесь на анализе кода части создания объекта.
WebMvcConfigurationSupport#createRequestMappingHandlerMapping
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
Код, который может создать объект RequestMappingHandlerMapping, очень прост, то есть для инициализации вызывается конструкция без параметров. Но, глядя на отношение наследования RequestMappingHandlerMapping, мы видим, что класс реализует интерфейс InitializingBean, который также говорит нам, что, когда мы видим очень простой код, нам нужно посмотреть на отношение наследования класса, чтобы решить, следует ли использовать другие. Форма для логической реализации.
Теперь, когда реализован интерфейс InitializingBean, посмотрите на метод инициализации afterPropertiesSet после создания bean-компонента.
@Override
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
// 调用父类的初始化方法
super.afterPropertiesSet();
}
@Override
public void afterPropertiesSet() {
// 初始化处理方法
initHandlerMethods();
}
Метод обработки инициализации: AbstractHandlerMethodMapping#initHandlerMethods
protected void initHandlerMethods() {
// 获取并遍历候选bean名称,候选bean就是从IOC容器中获取类型为Object的bean名称,也就是所有的Bean名称
for (String beanName : getCandidateBeanNames()) {
// 如果bean的名称不以“scopedTarget.”开头,才进行处理
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 处理候选bean名称
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
Обработка компонента Имя кандидата: AbstractHandlerMethodMapping # processCandidateBean
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
// 根据bean的名称获取对应bean的类型
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
// 如果bean的类型不为空并且对应类上含有@Controller注解或者@RequestMapping注解
if (beanType != null && isHandler(beanType)) {
// 推断处理方法
detectHandlerMethods(beanName);
}
}
Предполагаемый метод обработки: AbstractHandlerMethodMapping#detectHandlerMethods.
protected void detectHandlerMethods(Object handler) {
// 根据bean名称获取类型
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 获取处理方法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// selectMethods方法获取当前类中所有的方法,针对PersonController类就有list、get、add、update四个方法,遍历这四个方法,分别创建对应的RequestMappingInfo对象
// 根据method获取RequestMappingInfo对象
return getMappingForMethod(method, userType);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
Получить объект RequestMappingInfo в соответствии с методом: RequestMappingHandlerMapping#getMappingForMethod
@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 根据method对象创建RequestMappingInfo对象
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 如果当前方法所在的类也含有@RequestMapping对象,那么也创建一个RequestMappingInfo对象
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 将两个RequestMappingInfo对象进行合并,比如我们PersonController上指定@RequestMapping("/persons"),针对list方法,list方法上指定@RequestMapping("/"),那么合并后的映射路径就是/persons/
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).build().combine(info);
}
}
// 返回RequestMappingInfo对象
return info;
}
Вернемся к методу обработки логического вывода: AbstractHandlerMethodMapping#detectHandlerMethods.
protected void detectHandlerMethods(Object handler) {
// 根据bean名称获取类型
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 获取处理方法,每个方法都有对应的RequestMappingInfo对象
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// selectMethods方法中当前类中所有的方法,针对PersonController类就有list、get、add、update四个方法,遍历这四个方法,分别创建对应的RequestMappingInfo对象
// 根据method获取RequestMappingInfo对象
return getMappingForMethod(method, userType);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
// 遍历处理方法
methods.forEach((method, mapping) -> {
// 获取可以执行的method对象
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 注册处理方法
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
Метод обработки регистрации: AbstractHandlerMethodMapping.MappingRegistry#register
public void register(T mapping, Object handler, Method method) {
// 加写锁,加锁是因为我们可以在代码中手动注册处理方法,为了防止并发问题,此处需要加锁处理
this.readWriteLock.writeLock().lock();
try {
// 创建HandlerMethod对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
// 将RequestMappingInfo对象和HandlerMethod对象添加到map集合中
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
// 将url和RequestMappingInfo对象添加到map集合中
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
// 将RequestMappingInfo和MappingRegistration对象添加到map集合中
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
// 释放锁
this.readWriteLock.writeLock().unlock();
}
}
Результат после завершения обхода всех методов выглядит следующим образом:
На этом создание и инициализация объекта RequestMappingHandlerMapping завершены.
Сводка по созданию объекта RequestMappingHandlerMapping
Вызов метода инициализации afterPropertiesSet
получить все имена бобов
Перебрать все имена bean-компонентов и продолжить обработку, если имя bean-компонента не начинается с «scopedTarget».
Получите тип компонента в соответствии с именем компонента, узнайте, содержит ли соответствующий тип аннотацию @Controller или аннотацию @RequestMapping, и продолжите обработку, если да
Получить все методы в текущем классе, пройти по всем методам
Создайте объект RequestMappingInfo в соответствии с объектом Method. Если класс также аннотирован с помощью @RequestMapping, то также создается объект RequestMappingInfo, и два объекта RequestMappingInfo объединяются.
Просмотрите наборы карт, соответствующие Method и RequestMappingInfo, и зарегистрируйте их в соответствующих наборах mappingLookup, urlLookup и реестра.
Создать реквестмаппингхандлерадаптер
Создать RequestMappingHandlerAdapter: WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// 调用父类创建RequestMappingHandlerAdapter对象
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
// ...省略部分代码
return adapter;
}
Вызовите родительский класс для создания RequestMappingHandlerAdapter: WebMvcConfigurationSupport#requestMappingHandlerAdapter.
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// 创建RequestMappingHandlerAdapter对象
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
// 省略部分代码
return adapter;
}
обработка запроса
поток обработки запроса
Пройдите все объекты HandlerMapping, чтобы найти HandlerMethod, соответствующий текущему запросу.
Оберните HandlerMethod в объект HandlerExecutionChain
Найдите HandlerAdapter в соответствии с HandlerMethod
HandlerAdapter выполняет HandlerMethod
Сопоставьте HandlerMethod и оберните его в объект HandlerExecutionChain.
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerExecutionChain mappedHandler = null;
// 匹配HandlerMethod并包装成HandlerExecutionChain对象
mappedHandler = getHandler(processedRequest);
}
Получите объект HandlerExecutionChain: DispatcherServlet#getHandler
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍历所有的HandlerMapping
for (HandlerMapping mapping : this.handlerMappings) {
// 根据HandlerMapping获取HandlerExecutionChain对象,此处的HandlerMapping就是上面分析过的RequestMappingHandlerMapping对象
HandlerExecutionChain handler = mapping.getHandler(request);
// 如果获取到HandlerExecutionChain对象,那么直接将HandlerExecutionChain对象返回
if (handler != null) {
return handler;
}
}
}
return null;
}
Получите объект HandlerExecutionChain в соответствии с HandlerMapping: AbstractHandlerMapping#getHandler
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取HandlerMethod对象
Object handler = getHandlerInternal(request);
// ...省略部分代码
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// ...省略部分代码
return executionChain;
}
Получить объект HandlerMethod
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取请求的路径,假设此处请求的路径为/persons/
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 加锁
this.mappingRegistry.acquireReadLock();
try {
// 寻找HandlerMethod对象
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// 获取HandlerMethod所在类对应的bean,然后创建HandlerMethod对象
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
// 释放锁
this.mappingRegistry.releaseReadLock();
}
}
Найдите объект HandlerMethod: AbstractHandlerMethodMapping#lookupHandlerMethod.
Перед этим методом посмотрите на результаты анализа RequestMappingHandlerMapping выше.
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 从urlLookup属性中找到当前请求路径对应的RequestMappingInfo信息
// 假设请求的路径为/persons/,那么此处得到的结果有3个
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 寻找最匹配的RequestMappingInfo
// 匹配的方式包括:请求方法、请求header、请求参数等
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
// 如果存在多个匹配结果,就报错
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
// 返回匹配的HandlerMethod
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
getHandlerAdapter
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
}
Получить HandlerAdapter: DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 如果当前HandlerAdapter支持当前要处理的HnadlerMethod,那么就返回此HandlerAdapter
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");
}
Метод сопоставления: возьмите здесь в качестве примера RequestMappingHandlerAdapter и вызовите AbstractHandlerMethodAdapter#supports.
public final boolean supports(Object handler) {
// 如果当前的hander是HandlerMethod,则返回true;后一个表达式直接返回的就是true
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
Вывод, который можно сделать из приведенного выше анализа, заключается в том, что окончательный возвращенный HandlerAdapter — это RequestMappingHandlerAdapter.
HandlerAdapter выполняет HandlerMethod
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
Целевой метод обработки: RequestMappingHandlerAdapter#handleInternal
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
// ...省略部分代码
}
else {
// No synchronization on session demanded at all...
// 调用HandlerMethod方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// ...省略部分代码
return mav;
}
Вызовите метод HandlerMethod: RequestMappingHandlerAdapter#invokeHandlerMethod.
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 创建ServletInvocableHandlerMethod对象,就是把handlerMethod对象的属性赋值给ServletInvocableHandlerMethod对象的属性
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// ...省略部分代码
// 调用方法并处理返回值
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
Вызвать метод и обработать возвращаемое значение: ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 执行请求,获取返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
// ...省略部分代码
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 处理返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
}
Выполнить запрос: InvocableHandlerMethod#invokeForRequest
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取方法参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 目标方法调用
return doInvoke(args);
}
Вызов целевого метода: InvocableHandlerMethod#doInvoke
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 通过反射执行目标方法
return getBridgedMethod().invoke(getBean(), args);
}
// ...省略部分代码
}
На этом анализ исходного кода обработки запросов закончен, и наконец, давайте взглянем на метод doDispatch полностью: DispatcherServlet#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 {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 1、获取handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 2、获取HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
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;
}
// Actually invoke the handler.
// 调用目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 执行拦截器的处理方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 执行拦截器的后置方法,常用语释放资源
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 执行拦截器的后置方法,常用语释放资源
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
резюме автомобиля
Принцип запроса следующий:
инициализация запроса
обработка запроса
инициализация запроса
Инициализировать RequestMappingHandlerMapping
Инициализировать RequestMappingHandlerAdapter
обработка запроса
Получите HandlerMethod и соберите объект HandlerExecutionChain.
getHandlerAdapter
Выполнение HandlerMethod с помощью HandlerAdapter
Обзор автомобиля
Зачем мы добавляем метод в контроллер, аннотируем его аннотацией @RequestMapping, указываем путь, и его можно использовать для обработки веб-запроса? Поскольку в процессе инициализации путь запроса и метод обработки связаны, когда мы запрашиваем ulr, мы сопоставляем наш соответствующий метод обработки, а затем вызываем метод обработки для выполнения запроса ewb.
Если пути запросов нескольких методов согласованы, как с этим справляется Spring Boot? Если пути запроса нескольких методов совпадают, будут использоваться метод запроса, параметры запроса, заголовок запроса и т. д., и, наконец, будет сопоставлен наиболее подходящий метод обработки. При совпадении нескольких результатов будет сообщено об ошибке.
Проблема с пропавшим автомобилем
Как SpringBoot обрабатывает параметры запроса
Как SpringBoot обрабатывает возвращаемые результаты
Как работают перехватчики SpringBoot
Расширенный автомобиль
Если он основан на разработке микросервисов, как мы должны определить наш сервис?
Определите интерфейс микросервиса:
@RequestMapping("/persons")
public interface PersonApi {
/**
* list
*
* @return
*/
@GetMapping("/")
List<Person> list();
/**
* get
*
* @param id
* @return
*/
@GetMapping("/{id}")
Person get(@PathVariable("id") Integer id);
/**
* add
*
* @param person
* @return
*/
@PostMapping("/")
void add(@RequestBody Person person);
/**
* update
*
* @param person
* @return
*/
@PutMapping("/")
void update(@RequestBody Person person);
}
Определите реализацию интерфейса:
@RestController
public class PersonController implements PersonApi {
private static List<Person> personList = new ArrayList<>();
static {
personList.add(new Person(10001, "test1"));
personList.add(new Person(10002, "test2"));
personList.add(new Person(10003, "test3"));
personList.add(new Person(10004, "test4"));
personList.add(new Person(10005, "test5"));
}
@Override
public List<Person> list() {
return personList;
}
@Override
public Person get(Integer id) {
Person defaultPerson = new Person(88888, "default");
return personList.stream().filter(person -> Objects.equals(person.getId(), id)).findFirst().orElse(defaultPerson);
}
@Override
public void add(Person person) {
personList.add(person);
}
@Override
public void update(Person person) {
personList.removeIf(p -> Objects.equals(p.getId(), person.getId()));
personList.add(person);
}
}