Spring Boot超详细讲解请求处理流程机制

目录
  • 1. 背景
  • 2. Spring Boot 的请求处理流程设计
  • 3. Servlet服务模式请求流程分析
    • 3.1 ServletWebServerApplicationContext分析
    • 3.2 Servlet服务模式之请求流程具体分析
  • 4. Reactive服务模式请求流程分析
    • 4.1 ReactiveWebServerApplicationContext分析
    • 4.2 webflux服务模式之请求流程具体分析
  • 5. 总结

1. 背景

之前我们对Spring Boot做了研究讲解,我们知道怎么去集成配置, 知道它如何启动, 如何实现自动化配置,那么它如何接收并处理外部请求, 具体原理是怎样, 又要流转哪些关键环节? filter,interceptor, view是在哪调用, 处理顺序是怎样?Spring Boot 和Spring MVC以及内置容器又是怎样的作用关系? 这里我们作具体剖析研究。

2. Spring Boot 的请求处理流程设计

整理处理流程:

从流程图可以看到, 从内嵌的服务器接收请求到Spring Web包的处理, 再调用Spring MVC框架, 最后再到自定义的Controller。经过层层处理, 我们接下来再研究具体的处理机制。

UML关系图:

从UML图中可以看到, 层级较为复杂, 主要关注两个层面:

一是继承GenericWebApplicationContext类,具备上下文BEAN的管理能力;

另外是实现ConfigurableWebServerApplicationContext接口, 具备上下文配置能力。

3. Servlet服务模式请求流程分析

3.1 ServletWebServerApplicationContext分析

Spring Boot启动时,会判断应用服务类型, 有两种, 一种是Servlet服务, 另一种是Reactive响应式服务。ServletWebServerApplicationContext就是Servlet服务核心实现类。

它实现 ConfigurableWebServerApplicationContext 接口,继承 GenericWebApplicationContext 类:

public interface ConfigurableWebServerApplicationContext
		extends ConfigurableApplicationContext, WebServerApplicationContext {
	/**
	 * 设置服务的命名空间
	 */
	void setServerNamespace(String serverNamespace);
}

继承ConfigurableApplicationContext, WebServerApplicationContext两个接口, 并定义setServerNamespace接口, 设置服务的命名空间。

看下WebServerApplicationContext源码:

public interface WebServerApplicationContext extends ApplicationContext {
	/**
	 * 获取WebServer管理对象
	 */
	WebServer getWebServer();
	/**
	 * 获取服务的命名空间
	 */
	String getServerNamespace();
}

webServer是一个服务管理接口, 包含服务的启动与停止管理功能。

ServletWebServerApplicationContext 的构造方法:

   /**
	 * 默认构造方法
	 */
	public ServletWebServerApplicationContext() {
	}
	/**
	 * 指定beanFactory的构造方法
	 */
	public ServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
		super(beanFactory);
	}

支持传递指定beanFactory进行对象初始化。

ServletWebServerApplicationContext 的refresh方法:

@Override
public final void refresh() throws BeansException, IllegalStateException {
    try {
        // 由父类方法初始化Spring上下文
        super.refresh();
    }
    catch (RuntimeException ex) {
        // 如果异常, 停止WebServer启动并释放资源
        stopAndReleaseWebServer();
        throw ex;
    }
}

refresh()方法, 可以参考【Spring Boot启动流程】第一章的3.2.4章节第12点说明, 里面做了具体说明, 就不再赘述。

ServletWebServerApplicationContext 的createWebServer方法:

private void createWebServer() {
		WebServer webServer = this.webServer;
        // 获取ServletContext上下文
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
            // 如果为空, 则进行初始化创建
			ServletWebServerFactory factory = getWebServerFactory();
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
                // 如果不为空,则直接启动
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
    	// 初始化属性资源配置信息
		initPropertySources();
	}

ServletWebServerApplicationContext 的selfInitialize方法:

	private void selfInitialize(ServletContext servletContext) throws ServletException {
        // 将ServeltContext设置为WebApplicationContext相关属性
		prepareWebApplicationContext(servletContext);
        // 注册ApplicationScope作用域
		registerApplicationScope(servletContext);
        // 注册环境变量中的bean信息, 在BeanFactory中也可以获得servletContext上下文信息
		WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
            // 设置Bean在ServletContext加载完毕后进行初始化
			beans.onStartup(servletContext);
		}
	}

ServletWebServerApplicationContext 的finishRefresh方法:

	@Override
	protected void finishRefresh()
        // 完成刷新逻辑处理, 比如清除缓存, 发布刷新事件等
		super.finishRefresh();
		// 启动WebServer
		WebServer webServer = startWebServer();
		if (webServer != null)
            // 发布WebServer初始化完成事件
			publishEvent(new ServletWebServerInitializedEvent(webServer, this));
		}
	}

以上是整个Servlet模式服务的启动流程, ServletWebServerApplicationContext作为核心处理类,介绍了主要方法的处理逻辑 。

3.2 Servlet服务模式之请求流程具体分析

Spring Boot 是基于MVC做的封装,先看下Spring MVC的处理流程:

Spring Boot 默认是采用Tomcat作为容器, WebServer的实现类为TomcatWebServer, start启动方法:

    @Override
	public void start() throws WebServerException {
        // 增加同步锁
		synchronized (this.monitor) {
			if (this.started) {
                // 如果启动, 则直接返回
				return;
			}
			try {
                //处理tomcat的Connectors连接配置信息, 就是tomcat得xml配置得Connector信息
				addPreviouslyRemovedConnectors();
				Connector connector = this.tomcat.getConnector();
				if (connector != null && this.autoStart) {
                    // 如果存在Connector, 且为自动启动, 设置Tomcat的内置上下文延迟处理(服务成功启动后执行)
					performDeferredLoadOnStartup();
				}
                // 检查配置的Connectors是否已经启动, 避免冲突
				checkThatConnectorsHaveStarted();
				this.started = true;
				logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
						+ getContextPath() + "'");
			}
			catch (ConnectorStartFailedException ex) {
                // 出现异常, 静默停止
				stopSilently();
				throw ex;
			}
			catch (Exception ex) {
				if (findBindException(ex) != null) {
					throw new PortInUseException(this.tomcat.getConnector().getPort());
				}
				throw new WebServerException("Unable to start embedded Tomcat server", ex);
			}
			finally {
                // 获取TOMCAT内置上下文
				Context context = findContext();
                // 解除与classloader类加载器的绑定关系
				ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
			}
		}
	}

Web接口调用栈关系:

我们编写一个测试的Web接口, 看下其调用栈结构:

调用栈关系可以看到, 从tomcat的httpServlet接收到请求, 交给Spring MVC的DispatchServlet处理, 再分到我们自定义的WEB接口, 我们经常定义的过滤器Filter, 在进入httpServlet之前已经被处理。

DispatcherServlet的doService方法

我们查看下核心的, 请求分发处理流程:

    @Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception
		// LOG日志记录请求信息
		logRequest(request);
		// 记录Request级别作用域的请求变量信息, 必须要开启INCLUDE_REQUEST_URI_ATTRIBUTE属性
		Map<String, Object> attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap<>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}
		// 设置context上下文信息
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		// 设置locale区域信息
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		// 设置theme解析器
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		// 设置theme源信息
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
		// 设置flashmap信息, FlashMap 是传递重定向参数的时候要用到的一个类
		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 {
            // 分发请求, 对请求做真正的逻辑处理
			doDispatch(request, response);
		}
		finally {
            // 判断是否异步处理请求
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// 上面初始化设置attributesSnapshot, 这里如果有记录, 做还原处理
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

DispatcherServlet的doDispatch方法

doDispatch方法负责请求分发处理, 内部会找到我们定义的处理器, 负责处理具体的请求逻辑。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 定义初始变量
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
		// 获取Web异步请求管理器
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		try {
			ModelAndView mv = null;
			Exception dispatchException = null;
			try {
                // 检查请求是否为form-multipart提交类型,我们常见的文件上传就是采用此类型
				processedRequest = checkMultipart(request);
                // 如果是multipart该类型, 通过MultipartResolver解析
				multipartRequestParsed = (processedRequest != request);

				// 获取当前请求的映射处理器, 也就是自定义的controller, 如果没有找到, 则返回, 不做下面逻辑处理
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
				// 根据映射处理器, 获取处理适配器(实际为RequestMappingHandlerAdapter)
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				// 获取请求类型,包含GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS等
				String method = request.getMethod();
                // 判断是否为GET类型
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
                    // 获取上次请求修改标记, 如果没有修改, 默认返回-1
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				// 在进入处理器之前, 先要判断有没设置拦截器, 如果有, 进入拦截器的前置处理逻辑, 默认有ResourceUrlProviderExposingInterceptor等拦截器
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				// 这里就是真正调用处理器, 也就是我们在controller中定义的方法
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				// 异步处理判断
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				// 判断有没采用ModelAndView返回, 并进行对应设置
				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 {
				//如果采用multipart类型提交, 会做一些清除工作, 比如上传文件缓存等
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

通过以上分析, 我们可以了解到Servlet模式服务的请求流程, 重点是DispatcherServlet的doDispatch方法,要了解一个请求进入之前所做的事情, 请求处理完成之后所做的事情, 以及对于filter, interceptor执行顺序这些都要清楚, 可以帮助我们更好的运用, 以及排查请求过程中出现的问题。

4. Reactive服务模式请求流程分析

4.1 ReactiveWebServerApplicationContext分析

ReactiveWebServerApplicationContext为响应式服务容器管理, 是提供Reactive Web环境的Spring 容器。 Spring WebFlux应用就采用ReactiveWebServerApplicationContext实现, ReactiveWebServerApplicationContext与ServletWebServerApplicationContext 的实现类似, 都是由SpringBoot统一封装设计, 总体处理流程基本一致。

ReactiveWebServerApplicationContext 构造方法

public class ReactiveWebServerApplicationContext extends GenericReactiveWebApplicationContext
		implements ConfigurableWebServerApplicationContext {
	// 服务管理类, 包含服务启动与停止, 以及请求handler处理
	private volatile ServerManager serverManager;
	// 服务命名空间
	private String serverNamespace;
	/**
	 * 默认构造方法
	 */
	public ReactiveWebServerApplicationContext() {
	}
	/**
	 * 指定beanFactory的构造方法
	 */
	public ReactiveWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
		super(beanFactory);
	}

ReactiveWebServerApplicationContext#ServerManager内部类:

    /**
	 * 服务管理类
	 */
	static final class ServerManager implements HttpHandler {
		// WebServer服务
		private final WebServer server;
		// 是否懒加载
		private final boolean lazyInit;
		// Http Handler请求处理器
		private volatile HttpHandler handler;
		// 构造方法, 注入serverFactory与延迟加载标记
		private ServerManager(ReactiveWebServerFactory factory, boolean lazyInit) {
			this.handler = this::handleUninitialized;
			this.server = factory.getWebServer(this);
			this.lazyInit = lazyInit;
		}
		// 处理未初始化的请求, 暂未实现
		private Mono<Void> handleUninitialized(ServerHttpRequest request, ServerHttpResponse response) {
			throw new IllegalStateException("The HttpHandler has not yet been initialized");
		}
		// 重载方法, 处理Web请求
		@Override
		public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
			return this.handler.handle(request, response);
		}
		public HttpHandler getHandler() {
			return this.handler;
		}
		// 获取ServerManager服务管理类
		public static ServerManager get(ReactiveWebServerFactory factory, boolean lazyInit) {
			return new ServerManager(factory, lazyInit);
		}
        // 获取WebServer服务
		public static WebServer getWebServer(ServerManager manager) {
			return (manager != null) ? manager.server : null;
		}
        // 通过serverManager启动服务
		public static void start(ServerManager manager, Supplier<HttpHandler> handlerSupplier) {
			if (manager != null && manager.server != null) {
				manager.handler = manager.lazyInit ? new LazyHttpHandler(Mono.fromSupplier(handlerSupplier))
						: handlerSupplier.get();
				manager.server.start();
			}
		}
		// 通过serverManager停止服务
		public static void stop(ServerManager manager) {
			if (manager != null && manager.server != null) {
				try {
					manager.server.stop();
				}
				catch (Exception ex) {
					throw new IllegalStateException(ex);
				}
			}
		}
	}

ReactiveWebServerApplicationContext#startReactiveWebServer方法:

	private WebServer startReactiveWebServer() {
		ServerManager serverManager = this.serverManager;
        // 启动WebServer, 从BeanFactory中获取HttpHandler
		ServerManager.start(serverManager, this::getHttpHandler);
        // 获取返回WebServer
		return ServerManager.getWebServer(serverManager);
	}

查看getHttpHandler方法:

protected HttpHandler getHttpHandler() {
		// 获取所有实现HttpHandler接口的实现类
		String[] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class);
    	// HttpHandler实现类只能存在一个, 没有配置或多个都会抛出异常
		if (beanNames.length == 0) {
            //
			throw new ApplicationContextException(
					"Unable to start ReactiveWebApplicationContext due to missing HttpHandler bean.");
		}
    	// 存在多个, 抛出异常
		if (beanNames.length > 1) {
			throw new ApplicationContextException(
					"Unable to start ReactiveWebApplicationContext due to multiple HttpHandler beans : "
							+ StringUtils.arrayToCommaDelimitedString(beanNames));
		}
    	// 返回HttpHandler
		return getBeanFactory().getBean(beanNames[0], HttpHandler.class);
	}

ReactiveWebServerApplicationContext#onClose方法:

@Override
protected void onClose() {
    // 先调用父类方法, 关闭逻辑处理, 目前是空实现
    super.onClose();
    // 通过ServerManager停止服务
    stopAndReleaseReactiveWebServer();
}

4.2 webflux服务模式之请求流程具体分析

上面讲解了ReactiveWebServerApplicationContext的代码实现流程, 我们看下webflux服务的请求处理流程。

定义HttpHandler

// 定义Reactive服务的HttpHandler,
@Bean
public HttpHandler httpHandler() {
   return WebHttpHandlerBuilder.applicationContext(this.applicationContext)
         .build();
}

webflux使用的httpHandler类型是HttpWebHandlerAdapter, 创建的webserver为NettyWebServer类型

@Override
public WebServer getWebServer(HttpHandler httpHandler) {
   // 创建HTTP SERVER服务
   HttpServer httpServer = createHttpServer();
   // 定义HTTP HANDLER处理适配器
   ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(
         httpHandler);
   // 采用Netty作为WebServer实现
   return new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout);
}

创建ReactorHttpHandlerAdapter使用的httpHandler就是我们上面定义的WebHttpHandlerBuilder。

当一个请求进来的时候,就是通过ReactorHttpHandlerAdapter的apply()方法然后进入了了HttpWebHandlerAdapter类的handle方法, 再执行DispatcherHandler的handle方法:

public Mono<Void> handle(ServerWebExchange exchange) {
        // 校验handlerMappings是否存在
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
    	// 响应式操作, 调用Handler实现类处理逻辑, handleResult处理执行结果
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				.flatMap(handler -> invokeHandler(exchange, handler))
				.flatMap(result -> handleResult(exchange, result));
	}

通过RequestMappingHandlerMapping找到对应的HandlerMethod(就是我们Controller中对应的方法),然后执行invokeHandler方法:

	private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
        // 校验Handler适配器是否存在
		if (this.handlerAdapters != null) {
            // 遍历handlerAdapters
			for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
                // 判断是否支持的适配器类型
				if (handlerAdapter.supports(handler)) {
                    // 处理Handler适配器具体逻辑
					return handlerAdapter.handle(exchange, handler);
				}
			}
		}
		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
	}

HandlerAdapter是RequestMappingHandlerAdapter,在RequestMappingHandlerAdapter方法中执行了InvocableHandlerMethod的invode方法,然后通过反射执行了Controller中的方法, 最后把Controller方法执行的结果,通过DispatcherHandler中的handlerResult方法,输出返回给调用客户端。

5. 总结

学习研究Spring Boot的请求流程, 理解其内置容器, Spring MVC和自定义controller之间是如何流转处理的, 各自所做的事情, 每个环节的作用, 相互之间的调用关系, 才算是理解和掌握Spring Boot的使用, 在实际工作当中, 可能更多的是停留在使用层面, 但是如果能够对实现原理有进一步认知, 我们才知道更合理的去使用, 以及更高效的去排查使用过程当中出现的各种问题。

到此这篇关于Spring Boot超详细讲解请求处理流程机制的文章就介绍到这了,更多相关Spring Boot请求处理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot+vue完成发送接口请求显示响应头信息

    目录 基于 springboot+vue 的测试平台 一.后端实现 二.前端实现 1. 返回的数据放到 vuex 中 2. 从 vuex 中获取数据并展示 基于 springboot+vue 的测试平台 (练手项目)开发继续更新. 在接口编辑页中点击发送接口请求,除了显示响应体外,还可以显示响应头等辅助信息,今天完成这个功能的开发. 一.后端实现 后端主要是修改一下处理接口发送请求的方法apiTestRun,之前这个方法返回的直接就是一个响应体,现在修改成返回更多的内容. 如图所示,注释掉的部分

  • SpringBoot多线程进行异步请求的处理方式

    目录 SpringBoot多线程进行异步请求的处理 第一步:编写配置类 第二步:对方法使用注解标注为使用多线程进行处理 SpringBoot请求线程优化 使用Callable来实现 1.异步调用的另一种方式 3.Deferred方式实现异步调用 SpringBoot多线程进行异步请求的处理 近期在协会博客园中,有人发布了博客,系统进行查重的时候由于机器最低配置进行大量计算时需要十秒左右时间才能处理完,由于一开始是单例模式,导致,在某人查重的时候整个系统是不会再响应别的请求的,导致了系统假死状态,

  • Spring Boot请求处理之常用参数注解使用教程

    目录 请求处理-SpringBoot常用参数注解使用 1.@PathVariable注解 2.@RequestHeader注解 3.@RequestParam注解 4.@CookieValue注解 5.@RequestAttribute注解 6.@RequestBody注解 7.@MatrixVariable与UrlPathHelper 7.1.基本简介 7.2.MatrixVariable注解 7.3.使用细节 7.3.1.WebMvcAutoConfiguration自动装配 7.3.2.U

  • springboot项目完整后端请求Controller层优雅处理

    目录 前言 Controller 层参数接收 统一状态码 | 返回格式 | 封装 ResultVo 统一校验 | 原始做法 | @Validated 参数校验 | 优化异常处理 统一响应 | 统一包装响应 | NOT 统一响应 统一异常 前言 本篇主要要介绍的就是 controller 层的处理,一个完整的后端请求由 4 部分组成: 接口地址(也就是 URL 地址) 请求方式(一般就是 get.set,当然还有 put.delete) 请求数据(request,有 head 跟 body) 响应

  • Spring Boot中扩展XML请求与响应的支持详解

    前言 在之前的所有Spring Boot教程中,我们都只提到和用到了针对HTML和JSON格式的请求与响应处理.那么对于XML格式的请求要如何快速的在Controller中包装成对象,以及如何以XML的格式返回一个对象呢? 什么是xml文件格式 我们要给对方传输一段数据,数据内容是"too young,too simple,sometimes naive",要将这段话按照属性拆分为三个数据的话,就是,年龄too young,阅历too simple,结果sometimes naive.

  • Spring Boot详解各类请求和响应的处理方法

    目录 1. HttpServletRequest与HttpServletResponse 2. GET类型的请求 2.1 /students?current=1&limit=20 2.2 /student/123 3. POST类型的请求 4. 响应HTML格式的数据 4.1 使用ModelAndView 4.2 使用Model 5. 响应JSON格式的数据 5.1 单组数据 5.2 多组数据 1. HttpServletRequest与HttpServletResponse 浏览器输入:htt

  • springboot 全局异常处理和统一响应对象的处理方式

    目录 springboot异常处理 SpringBoot 默认的异常处理机制 SpringBoot 全局异常处理 1. 局部异常处理 2. 全局异常处理 自定义异常 统一响应对象 定义统一的响应对象 枚举信息 响应对象 springboot异常处理 SpringBoot 默认的异常处理机制 默认情况,SpringBoot 提供两种不同响应方式 一种是浏览器客户端请求一个不存在的页面或服务端异常时,SpringBoot默认会响应一个html 另一种是使用postman等调试工具请求不存在的url或

  • Spring Boot超详细讲解请求处理流程机制

    目录 1. 背景 2. Spring Boot 的请求处理流程设计 3. Servlet服务模式请求流程分析 3.1 ServletWebServerApplicationContext分析 3.2 Servlet服务模式之请求流程具体分析 4. Reactive服务模式请求流程分析 4.1 ReactiveWebServerApplicationContext分析 4.2 webflux服务模式之请求流程具体分析 5. 总结 1. 背景 之前我们对Spring Boot做了研究讲解,我们知道怎

  • Spring Boot超详细分析启动流程

    目录 一.Spring Boot 工程结构 二.Spring Boot 启动流程 三.Spring Boot 启动流程源码剖析 1.创建一个Spring Boot 工程 2.SpringBootApplication启动入口 3.Spring Boot 初始化分析 4.Spring Boot 启动深入分析 四.总结 一.Spring Boot 工程结构 下载Spring Boot工程源码, 下载地址 模块代码结构: 比较重要的是Spring-boot.Spring-boot-autoconfig

  • Python超详细讲解内存管理机制

    目录 什么是内存管理机制 一.引用计数机制 二.数据池和缓存 什么是内存管理机制 python中创建的对象的时候,首先会去申请内存地址,然后对对象进行初始化,所有对象都会维护在一 个叫做refchain的双向循环链表中,每个数据都保存如下信息: 1. 链表中数据前后数据的指针 2. 数据的类型 3. 数据值 4. 数据的引用计数 5. 数据的长度(list,dict..) 一.引用计数机制 引用计数增加: 1.1 对象被创建 1.2 对象被别的变量引用(另外起了个名字) 1.3 对象被作为元素,

  • Spring Boot示例分析讲解自动化装配机制核心注解

    目录 1. 自动化装配介绍 2. Spring Boot 自动化配置UML图解 3. Spring Boot 自动化配置核心注解分析 3.1 @Inherited 3.2 @SpringBootConfiguration 3.3 @EnableAutoConfiguration 3.4 @ComponentScan 3.5 @ConfigurationPropertiesScan 3.6 @AutoConfigurationImportSelector 3.7 @AutoConfiguratio

  • Java 超详细讲解Spring MVC异常处理机制

    目录 异常处理机制流程图 异常处理的两种方式 简单异常处理器SimpleMappingExceptionResolver 自定义异常处理步骤 本章小结 异常处理机制流程图 系统中异常包括两类: 预期异常 通过捕获异常从而获取异常信息. 运行时异常RuntimeException 主要通过规范代码开发.测试等手段减少运行时异常的发生. 系统的Dao.Service.Controller出现都通过throws Exception向上抛出,最后SpringMVC前端控制器交由异常处理器进行异常处理,如

  • Spring超详细讲解创建BeanDefinition流程

    目录 一.前期准备 1.1 环境依赖 1.2 实体类 1.3 applicationContext.xml 1.4 测试代码 二.探究过程 2.1 目标 2.2 BeanDefinition的创建过程 2.2.1 回顾bean对象的创建 2.2.2 AbstractApplicationContext 2.2.3 AbstractXmlApplicationContext 2.2.4 AbstractBeanDefinitionReader 2.2.5 XmlBeanDefinitionRead

  • Spring超详细讲解事务和事务传播机制

    目录 为什么需要事务 Spring 声明事务 Transactional参数说明 propagation isolation timeout 事务回滚失效解决方案 @Transactional工作原理 Spring 事务的传播机制 为什么需要事务传播机制? 传播机制的类型 为什么需要事务 事务是将一组操作封装成一个执行单元,要么全部成功,要么全部失败.如果没有事务,转账操作就会出现异常,因此需要保证原子性. Spring 声明事务 只需要在方法上添加@Transactional注解就可以实现,无

  • Spring超详细讲解注解开发

    目录 1.使用注解开发 1.1.Bean的实现 1.2.属性注入 1.3.衍生注解 1.4.自动装配注解 1.5.作用域 1.6.小结 2.基于Java类进行配置 1.使用注解开发 说明 在spring4之后,想要使用注解形式,必须得要引入aop的包 在配置文件当中,还得要引入一个context约束 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.spring

  • MyBatis插件机制超详细讲解

    目录 MyBatis的插件机制 InterceptorChain MyBatis中的Plugin MyBatis插件开发 总结 MyBatis的插件机制 MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用.默认情况下,MyBatis 允许使用插件来拦截的方法调用包括: Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler(

  • React渲染机制超详细讲解

    目录 准备工作 render阶段 workloopSync beginWork completeWork commit阶段 commitWork mutation之前 mutation fiber树切换 layout layout之后 总结 准备工作 为了方便讲解,假设我们有下面这样一段代码: function App(){ const [count, setCount] = useState(0) useEffect(() => { setCount(1) }, []) const handl

随机推荐