源码梳理(2)SpringMVC的执行流程及涉及到的相关组件

文章目录

          • 1,Spring MVC核心组件DispatcherServlet
            • 1.1 DispatcherServlet的继承关系
            • 1.2 DispatcherServlet的doDispatch方法
          • 2,核心组件HandlerMapping(处理器映射器)
          • 3,核心组件HandlerAdapter(处理器适配器)
          • 4,HandlerInterceptor拦截器
          • 5,核心组件Handler(处理器)
          • 6,ModelAndView(模型和视图)
          • 7,核心组件HandlerExceptionResolver(异常处理器解析器)

1,Spring MVC核心组件DispatcherServlet

所有源码都来自springboot3.0.2,spring-webmvc-6.0.4

1.1 DispatcherServlet的继承关系

DispatcherServlet的继承关系

HttpServlet是抽象类,用于处理基于HTTP协议的请求和响应。

package jakarta.servlet.http;

public abstract class HttpServlet extends GenericServlet

HttpServletBean是Spring Framework中提供的一个抽象基类,用于简化开发自定义的Servlet类在 Spring环境中的配置和使用。

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware

FrameworkServlet是Spring MVC框架中的一个重要组件,它是 DispatcherServlet的抽象基类之一。作为一个抽象类,FrameworkServlet提供了一些基本的功能,比如Servlet生命周期管理等

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware

DispatcherServlet是Spring MVC 框架中的核心组件,实现整个请求处理的流程,接下来会做详细分析

public class DispatcherServlet extends FrameworkServlet
1.2 DispatcherServlet的doDispatch方法

当HTTP请求打到服务器后,会先经过HttpServlet的service方法,然后执行到FrameworkServlet重写的service方法

	// HttpServlet.class
    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {
        HttpServletRequest  request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
        // FrameworkServlet重写了这个方法
        service(request, response);
    }

FrameworkServlet的service方法,如果是"DELETE", “HEAD”, “GET”, “OPTIONS”, “POST”, “PUT”, "TRACE"方法的请求会交给父类也就是HttpServlet的另一个(参数是HttpServletRequest,HttpServletResponse重载的)service方法,该service方法会根据请求类型,将任务再分发给doGet(),doPost()等方法,而这写方法都被FrameworkServlet重写了

	// FrameworkServlet.class
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		if (HTTP_SERVLET_METHODS.contains(request.getMethod())) {
			super.service(request, response);
		}
		else {
			processRequest(request, response);
		}
	}

FrameworkServlet重写的doGet,doPost等方法都是调用了processRequest方法

	// FrameworkServlet.class
	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		processRequest(request, response);
	}
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		processRequest(request, response);
	}

FrameworkServlet的核心方法processRequest,作用于处理客户端请求的整个流程,包括初始化上下文、调用doService方法处理请求、记录请求处理的结果和时间、无论结果如何发布请求处理完毕事件等。其中处理请求的核心方法doService由子类DispatcherServlet重写实现

	// FrameworkServlet.class
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 省略...
		try {
			// DispatcherServlet重写了这个方法
			doService(request, response);
		}
		// 省略...
	}

DispatcherServlet的doService方法的核心环节doDispatch方法

	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 省略...
		try {
			doDispatch(request, response);
		}
		// 省略...
	}

DispatcherServlet的doDispatch方法

	// DispatcherServlet.class
	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.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
				// 确定当前请求的处理器适配器
				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(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 ServletException("Handler dispatch failed: " + err, err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new ServletException("Handler processing failed: " + err, 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);
				}
			}
		}
	}
2,核心组件HandlerMapping(处理器映射器)

HandlerMapping是处理器映射器,其作用是根据请求的URL路径,通过注解或者XML配置,寻找匹配的处理器(Handler)信息。

	HandlerExecutionChain mappedHandler = null;
	// 省略...
	mappedHandler = getHandler(processedRequest);

在doDispatcher方法中,通过执行getHandler方法,获取到HandlerExecutionChain处理器执行链,并且准备好了针对当前请求最佳的处理器(比如自定义Controller组件中请求映射符合当前请求URL路径的某个方法),以及拦截器集合

	// DispatcherServlet.class
	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

HandlerExecutionChain的主要属性

// 处理器执行链
public class HandlerExecutionChain {
	// 处理器
	private final Object handler;
	// 拦截器集合
	private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
	// 拦截器索引
	private int interceptorIndex = -1;
	// 省略...
}
3,核心组件HandlerAdapter(处理器适配器)

HandlerAdapter 是处理器适配器,其作用是根据映射器找到的处理器(Handler)信息,按照特定规则执行相关的处理器(Handler)

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

在doDispatcher方法中,通过执行getHandlerAdapter方法,遍历所有处理器适配器,返回支持当前处理器的HandlerAdapter处理器适配器

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				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");
	}

HandlerAdapter接口的两个方法

public interface HandlerAdapter {
	// 配置当前处理器适配器是否支持传入的处理器
	boolean supports(Object handler);
	// 执行处理
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
4,HandlerInterceptor拦截器

HandlerInterceptor的三个方法:
preHandle方法在处理程序执行之前被调用。它可以拦截请求,并在处理程序执行之前进行一些预处理操作。方法返回一个布尔值,如果是true,则继续执行处理程序;如果是false,则终止请求的处理。
postHandle 方法在处理程序执行之后、视图渲染之前被调用。它允许拦截并修改处理程序的结果模型和视图。您可以在此方法中添加一些公共的模型数据、修改视图或进行一些资源清理操作。
afterCompletion 方法是在整个请求处理完成后被调用,包括视图渲染完毕。此时拦截器可以进行一些资源清理工作,或者进行一些日志记录等。它接收一个 Exception 参数,用于捕获并处理请求处理过程中的异常。

public interface HandlerInterceptor {
	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return true;
	}
	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}
	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}
}

DispatcherServlet的doServlet方法中拦截器的处理时机

	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 省略...
		try {
			// 省略...
			try {
				// 省略...
				// 执行HandlerInterceptor的preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				// 执行处理程序
				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				applyDefaultViewName(processedRequest, mv);
				//  执行HandlerInterceptor的postHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			// 省略...
			// 在processDispatchResult方法最后调用了mappedHandler.triggerAfterCompletion(request, response, null)执行HandlerInterceptor的afterCompletion方法
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		// 省略
	}
5,核心组件Handler(处理器)

Handler是处理器,和Java Servlet扮演的角色一致。HandlerAdapter接口的handle方法通过Handler执行相关的请求处理逻辑,并返回相应的数据和视图信息,将其封装至ModelAndView对象中。

	ModelAndView mv = null;
	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

RequestMappingHandlerAdapter的继承关系

举例当HandlerAdapter的实现类RequestMappingHandlerAdapter调用handle方法时,因为自身没有实现handle方法,所以会执行父类AbstractHandlerMethodAdapter的handle方法,这个handle的类型是HandlerMethod。

	@Override
	@Nullable
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return handleInternal(request, response, (HandlerMethod) handler);
	}

RequestMappingHandlerAdapter实现了handleInternal方法,走后面的处理逻辑最终处理并返回ModelAndView

	@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) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}

		return mav;
	}
6,ModelAndView(模型和视图)

handle处理程序返回的模型和视图,该模型和视图将由 DispatcherServlet 解析。视图可以是String 类型的视图名称,该名称需要由ViewResolver对象解析也可以直接指定View对象。该模型是一个 Map用于存储传输数据。

public class ModelAndView {

	/** View instance or view name String. */
	@Nullable
	private Object view;

	/** Model Map. */
	@Nullable
	private ModelMap model;

	/** Optional HTTP status for the response. */
	@Nullable
	private HttpStatusCode status;
}
7,核心组件HandlerExceptionResolver(异常处理器解析器)

HandlerExceptionResolver
异常处理器解析器是用于处理全局异常的组件,它可以捕获和处理控制器抛出的异常,然后决定如何对异常进行处理,例如返回错误页面、返回 JSON 错误信息等。
HandlerExceptionResolver接口就一个resolveException方法,通过这个方法来进行异常处理。

public interface HandlerExceptionResolver {
	@Nullable
	ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}

在DispatcherServlet的doDispatch执行到processDispatchResult方法的时候,会在前面处理请求过程中捕获的可能出现的异常作为参数传递进去

	// DispatcherServlet.class
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		try {
			ModelAndView mv = null;
			Exception dispatchException = null;
			try {
				// 省略...
			}
			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 ServletException("Handler dispatch failed: " + err, err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		// 省略...
	}

如果传递的异常参数不为null,且不属于ModelAndViewDefiningException,则走processHandlerException方法的异常处理逻辑,并通过异常处理结果获得新的ModelAndView

	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				// 异常处理
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
		if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isTraceEnabled()) {
				logger.trace("No view rendering, null ModelAndView returned.");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if (mappedHandler != null) {
			// Exception (if any) is already handled..
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

在processHandlerException方法中将遍历HandlerExceptionResolver并执行resolveException方法进行实际异常逻辑的处理,整个方法执行完则返回一个新的ModelAndView

	@Nullable
	protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
			@Nullable Object handler, Exception ex) throws Exception {
		// Success and error responses may use different content types
		request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
		// Check registered HandlerExceptionResolvers...
		ModelAndView exMv = null;
		if (this.handlerExceptionResolvers != null) {
			for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
				// 核心环节,遍历并执行HandlerExceptionResolver的resolveException方法
				exMv = resolver.resolveException(request, response, handler, ex);
				if (exMv != null) {
					break;
				}
			}
		}
		if (exMv != null) {
			if (exMv.isEmpty()) {
				request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
				return null;
			}
			// We might still need view name translation for a plain error model...
			if (!exMv.hasView()) {
				String defaultViewName = getDefaultViewName(request);
				if (defaultViewName != null) {
					exMv.setViewName(defaultViewName);
				}
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Using resolved error view: " + exMv, ex);
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Using resolved error view: " + exMv);
			}
			WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
			return exMv;
		}

		throw ex;
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/371808.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端文艺复兴:Vue3真的需要Pinia吗?

前言 说起Pinia&#xff0c;熟悉 vue3 开发的程序员肯定不会陌生&#xff0c;甚至被vue官方推荐取代vuex&#xff0c;成为vue全家桶之一。 疑惑 还记得之前用 vuex 时&#xff0c;更改 state 还分同步和异步&#xff08;这里有尤雨溪的回答www.zhihu.com/question/48… &…

Hadoop-生产调优

第1章 HDFS-核心参数 1.1 NameNode内存生产配置 1&#xff09;NameNode 内存计算 每个文件块大概占用 150 byte&#xff0c;一台服务器 128G 内存为例&#xff0c;能存储多少文件块呢&#xff1f; 128 * 1024 * 1024 * 1024 / 150byte ≈ 9.1 亿G MB KB Byte 2&#xff09…

undefined symbol: avio_protocol_get_class, version LIBAVFORMAT_58

rv1126上进行编译和在虚拟机里面进行交叉编译ffmpeg都不行 解决办法查看 查看安装的ffmpeg链接的文件 ldd ./ffmpeg rootEASY-EAI-NANO:/home/nano/ffmpeg-4.3.6# ldd ffmpeg linux-vdso.so.1 (0xaeebd000)libavdevice.so.58 > /lib/arm-linux-gnueabihf/libavde…

continue语句

一、continue语句 1、continue语句介绍 2、continue语句流程图 3、快速入门案例 4、continue语句的标签

基于Go-Kit的Golang整洁架构实践

如何用Golang实现简洁架构&#xff1f;本文介绍了基于Go-Kit实现简洁架构的尝试&#xff0c;通过示例介绍了简洁架构的具体实现。原文: Why is Go-Kit Perfect For Clean Architecture in Golang? 简介 Go是整洁架构(Clean Architecture)的完美选择。整洁架构本身只是一种方法…

基于python+控制台的车辆信息管理系统

基于python控制台的车辆信息管理系统 一、系统介绍二、效果展示三、其他系统实现四、获取源码 一、系统介绍 打印功能菜单、添加车辆信息、删除车辆信息、修改车辆信息、显示车辆信息、退出系统&#xff0c;并且需要接收用户的输入&#xff0c;在根据输入内容调用相应函数实现…

深度学习介绍

对于具备完善业务逻辑的任务&#xff0c;大多数情况下&#xff0c;正常的人都可以给出一个符合业务逻辑的应用程序。但是对于一些包含超过人类所能考虑到的逻辑的任务&#xff0c;例如面对如下任务&#xff1a; 编写一个应用程序&#xff0c;接受地理信息、卫星图像和一些历史…

指针的深入理解(四)

这节主要讨论sizeof和strlen的区别&#xff0c;以及一些理解题。 sizeof 求的是对象的大小&#xff0c;深入理解一点就是&#xff1a;这个对象&#xff0c;他一定有一块对应的内存空间。求的就是这一块内存空间。 strlen 只能用来求字符串&#xff0c; 求取的是字符串的长度。…

Unity中blendtree和state间的过渡

混合树状态之间的过渡 如果属于此过渡的当前状态或下一状态是混合树状态&#xff0c;则混合树参数将出现在 Inspector 中。通过调整这些值可预览在混合树值设置为不同配置时的过渡表现情况。 如果混合树包含不同长度的剪辑&#xff0c;您应该测试在显示短剪辑和长剪辑时的过渡表…

Mocaverse NFT 概览与数据分析

作者&#xff1a;stellafootprint.network 编译&#xff1a;mingfootprint.network 数据源&#xff1a;Mocaverse NFT Collection Dashboard Mocaverse 是 Animoca Brands 推出的专属 NFT&#xff08;非同质化代币&#xff09;系列&#xff0c;包含 8,888 个独特的 "M…

深入理解TCP网络协议(3)

目录 1.前言 2.流量控制 2.阻塞控制 3.延时应答 4.捎带应答 5.面向字节流 6.缓冲区 7.粘包问题 8.TCP异常情况 9.小结 1.前言 在前面的博客中,我们重点介绍了TCP协议的一些属性,有连接属性的三次握手和四次挥手,还有保证数据安全的重传机制和确认应答,还有为了提高效率…

2024美赛E题成品论文22页详细讲解+完整代码数据汇总

E题社区抗灾能力综合评估与决策模型研究 &#xff08;完整版在文末&#xff09; 摘要&#xff1a;社区抗灾能力的提升对于灾害风险管理至关重要。本研究基于机器学 习方法&#xff0c;构建了社区抗灾能力预测模型&#xff0c;以评估社区在灾害事件中的表现。首先&#xff0c; 我…

在maven环境中使用GraalVM来构建本地原生应用程序(一)构建本地可执行文件

文章目录 前言一、GraalVM安装二、初步使用三、踩坑记录1、JSON转换问题2、反射、资源、jni的调用问题3、HTTPS调用问题4、Linux下CPU架构问题5、Linux下GLIBC版本的问题6、部分Windows系统无法缺少相关的库文件 总结 前言 随着Java17的更新&#xff0c;jdk又推出了一个GraalV…

【lesson10】高并发内存池细节优化

文章目录 大于256KB的大块内存申请问题大于256KB的大块释放申请问题使用定长内存池脱离使用new释放对象时优化为不传对象大小完整版代码Common.hObjectPool.hThreadCache.hThreadCache.cppConcurrentAlloc.hCentralCache.hCentralCache.cppPageCache.hPageCache.cpp 大于256KB的…

SpringBoot中数据库的连接及Mybatis的配置和使用

目录 1 在pom.xml中引入相关依赖 2 对数据库进行配置 2.1 配置application.yml 2.2 idea连接数据库 (3.2.1有用到) 3 Mybatis的使用 3.1 测试文件的引入 3.2 使用 3.2.1 使用注解(有小技巧(✪ω✪)) 3.2.2 使用动态sql 1 在pom.xml中引入相关依赖 <dependencies&g…

【DDD】学习笔记-EAS 的整体架构实践

为了得到系统的整体架构&#xff0c;我们还欠缺什么呢&#xff1f;所谓“架构”&#xff0c;是“以组件、组件之间的关系、组件与环境之间的关系为内容的某一系统的基本组织结构&#xff0c;以及指导上述内容设计与演化的原则”。之所以要确定系统的组件、组件关系以及设计与演…

线上编程答疑解惑回顾,初学编程中文编程在线屏幕共享演示

线上编程答疑解惑回顾&#xff0c;初学编程中文编程在线屏幕共享演示 一、学编程过程中有不懂的怎么办&#xff1f; 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载——常用工具下载——编…

基于深度学习的SSVEP分类算法简介

基于深度学习的SSVEP分类算法简介 1、目标与范畴2、深度学习的算法介绍3、参考文献 1、目标与范畴 稳态视觉诱发电位&#xff08;SSVEP&#xff09;是指当受试者持续注视固定频率的闪光或翻转刺激时&#xff0c;在大脑枕-额叶区域诱发的与刺激频率相关的电生理信号。与P300、运…

【C/C++ 12】C++98特性

目录 一、命名空间 二、缺省参数 三、函数重载 四、引用 五、内联函数 六、异常处理 一、命名空间 在C/C项目中&#xff0c;存在着大量的变量、函数和类&#xff0c;这些变量、函数和类都存在于全局作用域中&#xff0c;可能会导致命名冲突。 使用命名空间的目的就是对…

Gateway API 实践之(七)FSM Gateway 的负载均衡算法

FSM Gateway 流量管理策略系列&#xff1a; 故障注入黑白名单访问控制限速重试会话保持健康检查负载均衡算法TLS 上游双向 TLS 在微服务和 API 网关架构中&#xff0c;负载均衡是至关重要的&#xff0c;它确保每个服务实例都能平均地处理请求&#xff0c;同时也为高可用性和故…