Spring MVC源码详解

news2024/11/24 7:15:44

什么是Spring MVC ?

Spring MVC就是Spring+MVC。
Spring就不介绍了,什么是MVC?

  • M:模型,javabean
  • V:视图,如jsp
  • C:控制层,如Controller、Servlet

SpringMVC请求处理流程

在这里插入图片描述

  1. 用户发送请求至前端控制器DispatcherServlet;
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器;
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)HandlerExecutionChain一并返回给DispatcherServlet;
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器,执行处理器(Controller,也叫后端控制器);
  5. Controller执行完成返回ModelAndView,并返回给HandlerAdapter,HandlerAdapter将结果返回给DispatcherServlet;
  6. DispatcherServlet将ModelAndView传给ViewReslover视图解析器,ViewReslover解析后返回具体View给DispatcherServlet;
  7. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)后返回给给客户;

源码分析

代码调试准备

新建项目

新建Springboot项目,依赖如下:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

打断点

断点打在下面的位置:
org.springframework.web.servlet.DispatcherServlet#initStrategies:初始化阶段
org.springframework.web.servlet.DispatcherServlet#doDispatch:运行调用阶段。

项目调试启动时未进入上面的两个方法,当第一次调用Controller的请求时,会执行初始化阶段代码,每次调用Controller都会调用运行调用阶段代码。

初始化阶段

initStrategies方法初始化

第一次调用Controller时,会调用org.springframework.web.servlet.DispatcherServlet#initStrategies方法初始化SpringMVC的九大组件

protected void initStrategies(ApplicationContext context) {
		//多文件上传组件
		initMultipartResolver(context);
		//初始化本地语言环境
		initLocaleResolver(context);
		//初始化模版处理器
		initThemeResolver(context);
		//初始化处理器映射器
		initHandlerMappings(context);
		//初始化处理器适配器
		initHandlerAdapters(context);
		//初始化异常拦截器
		initHandlerExceptionResolvers(context);
		//初始化视图预处理器
		initRequestToViewNameTranslator(context);
		//初始化视图解析器
		initViewResolvers(context);
		//初始化FlashMap管理器
		initFlashMapManager(context);
	}

org.springframework.web.servlet.DispatcherServlet#initStrategies方法的调用链路如下:
在这里插入图片描述

HandlerMapping初始化

HandlerMapping是处理器映射器,简单讲是Controller中的方法与请求地址的映射关系,通过它可以找到Controller中的方法来处理请求。

什么是Handler?

Handler是controller中带请求路径的方法,最常用的是Controller中@RequestMapping注解标注的方法。如下面getProduct方法是Handler,loginPage方法不是Handler。

@Controller
@Slf4j
public class ClassifyController {
    @Autowired
    IClassifyService classifyService;




    @RequestMapping("/getClassify")
    @ResponseBody
    Object getProduct(){
        log.error("你妹的");
       return classifyService.selectByTenant("0000000001");
    }
//    @GetMapping("/index")
    public String loginPage(Model model){
        model.addAttribute("name","登科");
        return "welcom";
    }

}

Spring中共四种Handler

  • 加RequestMapping注解的方法(常用的)
  • 实现Controller接口的Bean对象(古老的方法)
  • 实现HttpRequestHandler接口的Bean对象(古老的方法)
  • HandlerFunction对象(新的)

什么是HandlerMapping?

HandlerMapping是处理器映射器,简单讲是Controller中的方法与请求地址的映射关系,通过它可以找到Controller中的方法来处理请求。

三种常用的HandlerMapping

  • BeanNameUrlHandlerMapping:处理实现Controller、HttpRequestHandler接口的Bean对象对应的Handler
  • RequestMappingHandlerMapping:处理加RequestMapping注解的方法对应的Handler,也是最常用的。
  • RouterFunctionMapping:处理HandlerFunction对象对应的Handler

HandlerMapping初始化源码分析

private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			//获取所有的HandlerMappings,其中包括RequestMappingHandlerMapping
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				//将获取到HandlerMapping赋值给DispatcherServlet.handlerMappings 
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

下面的代码获取了所有的HandlerMapping,其中包括RequestMappingHandlerMapping

Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

以RequestMappingHandlerMapping为例,HandlerMapping中是如何为何请求地址与Handler之间的映射呢?

上面的方法通过BeanFactory获取RequestMappingHandlerMapping对应的实例,因为RequestMappingHandlerMapping是单例的,容器启动的时候会创建单例对象。查看RequestMappingHandlerMapping的父类,实现了InitializingBean接口,因此创建实例的时候会执行初始化方法,而绑定请求地址与Handler的逻辑就在初始化方法中。

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#afterPropertiesSet

public void afterPropertiesSet() {
		this.config = new RequestMappingInfo.BuilderConfiguration();
		this.config.setUrlPathHelper(getUrlPathHelper());
		this.config.setPathMatcher(getPathMatcher());
		this.config.setSuffixPatternMatch(useSuffixPatternMatch());
		this.config.setTrailingSlashMatch(useTrailingSlashMatch());
		this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
		this.config.setContentNegotiationManager(getContentNegotiationManager());
		//跳转到父类的初始化方法
		super.afterPropertiesSet();
	}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet

@Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods

protected void initHandlerMethods() {
		for (String beanName : getCandidateBeanNames()) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				//绑定url与Handler的逻辑
				processCandidateBean(beanName);
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#processCandidateBean

protected void processCandidateBean(String beanName) {
		Class<?> beanType = null;
		try {
			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);
			}
		}
		//isHandler方法就是判断这个bean是否是Controller(有@Controller或者@RequestMapping注解)
		if (beanType != null && isHandler(beanType)) {
			detectHandlerMethods(beanName);
		}
	}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#detectHandlerMethods
根据给定的Controller,找出这个Controller中的所有Handler,也就是带@RequestMapping注解的方法

protected void detectHandlerMethods(Object handler) {
		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 {
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					});
			if (logger.isTraceEnabled()) {
				logger.trace(formatMappings(userType, methods));
			}
			methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}

最后通过org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod方法将映射关系维护到org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#registry对应的Map中。key是mapping对象,其实就是@RequestMapping注解中对应的信息,value是MappingRegistration对象。

		private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

MappingRegistration中

  • mapping是@RequestMapping注解中对应的信息

  • handlerMethod是Handler,也就是@RequestMapping注解的方法

  • directUrl是请求地址,这里观察是/getClassify

  • mappingName是映射的名称,这里观察室CC#getProduct

private static class MappingRegistration<T> {

		private final T mapping;

		private final HandlerMethod handlerMethod;

		private final List<String> directUrls;

		@Nullable
		private final String mappingName;
		............
}

HandlerMapping初始化总结

  • org.springframework.web.servlet.DispatcherServlet#initStrategies:初始化SpringMVC的九大组件。第一次调用请求Controller时,会初始化DispatcherServlet,因此会调用该方法
  • org.springframework.web.servlet.DispatcherServlet#initHandlerMappings:初始化处理器映射器
  • 获取所有的处理器映射器实例,并放入到org.springframework.web.servlet.DispatcherServlet#handlerMappings中,其实是List。以RequestMappingHandlerMapping这个处理器映射器为例子,因为RequestMappingHandlerMapping是单例、非延时加载,因此启动项目时会实例化该对象,handlerMappings是直接从缓存中获取的对象。
  • 实例化RequestMappingHandlerMapping对象时会调用初始化方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#afterPropertiesSet
  • 初始化方法会调用父类初始化方法org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet
  • 父类初始化方法中会调用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#initHandlerMethods
  • initHandlerMethods方法中会调用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#processCandidateBean
  • processCandidateBean方法中,会判断是否为Controller,如果是则调用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#detectHandlerMethods,该方法会查找Controller中所有的Handler,也就是该Controller所有标注@RequestMapping注解的方法,并解析注册到org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#registry中 。
  • 最终请求相关的信息和Handler就会绑定在一起,存储在HandlerMapping中。

运行调用阶段

随便调用一个Controller中的请求,会访问到org.springframework.web.servlet.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.
				//根据请求获取handler,获取到的是HandlerExecutionChain,HandlerExecutionChain中包括handler和interceptors
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					//走没有Handler的逻辑,404
					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 = "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.
				//调用handler,也就是Controller中对应的@RequestMapping注解的方法,并返回ModelAndView
				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);
				}
			}
		}
	}

根据请求获取Handler

下面的代码是根据请求获取handler,获取到的是HandlerExecutionChain,HandlerExecutionChain中包括handler和interceptors。

mappedHandler = getHandler(processedRequest);

org.springframework.web.servlet.DispatcherServlet#getHandler方法,遍历所有的handlerMapping,其中包括RequestMappingHandlerMapping,根据Request通过HandlerMapping获取Handler。

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;
	}

org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler方法,根据请求获取HandlerExecutionChain。HandlerExecutionChain中包含handler和interceptors。因为初始化阶段初始化HandlerMapping时,已经将请求信息与Handler绑定到一起,所以这里可以通过绑定信息获取,不继续往下跟了。

根据请求获取HandlerAdapter

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

之前初始化阶段也初始化了HandlerAdapter,因此有下面的几个:
在这里插入图片描述
org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter方法中,循环遍历HandlerAdapter,匹配到则返回,这里匹配到了RequestMappingHandlerAdapter。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {//初始化阶段获取的实例
			for (HandlerAdapter adapter : this.handlerAdapters) {//遍历所有的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");
	}

调用通过HandlerAdapter调用handler

这里执行了Controller中@RequestMapping注解的方法,走到了请求真正想处理的逻辑,并返回ModelAndView

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle方法:

@Override
	@Nullable
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}

调用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal方法

调用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

上面的方法中通过下面代码,最终通过反射调用方法。

invocableMethod.invokeAndHandle(webRequest, mavContainer);

视图解析器返回View,并渲染页面

org.springframework.web.servlet.DispatcherServlet#processDispatchResult

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);
		}
	}

获取视图并进行页面渲染

if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}

org.springframework.web.servlet.DispatcherServlet#render
方法中

//根据视图解析器获取视图,这里的视图解析器是初始化的时候通过initViewResolvers方法获取的
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {

		if (this.viewResolvers != null) {
			for (ViewResolver viewResolver : this.viewResolvers) {
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
					return view;
				}
			}
		}
		return null;
	}

org.springframework.web.servlet.DispatcherServlet#render方法中的下面代码,对视图进行渲染。

view.render(mv.getModelInternal(), request, response);

SpringMVC运行调用阶段源码总结

  • org.springframework.web.servlet.DispatcherServlet#getHandler:根据请求通过HandlerMapping获取Handler
  • org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter:根据Handler获取HandlerAdapter
  • org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle:调用HandlerAdap的handle方法,执行Handler(Controller中的方法)中的逻辑,返回ModelAndView。
  • org.springframework.web.servlet.DispatcherServlet#processDispatchResult:处理视图相关逻辑
  • org.springframework.web.servlet.DispatcherServlet#resolveViewName:根据视图解析器获取视图View
  • 调用View的render方法渲染jsp页面

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图像处理(空域变换(上))

数字图像处理 参考视频 Task 1 亮度变换 1. 幂律变换 伽马变换本质上是对图像矩阵中的每个值进行幂运算。 幂函数 s c r γ ( r ∈ [ 0 , 1 ] ) \text{幂函数}scr^γ(r\in[0,1]) 幂函数scrγ(r∈[0,1]) 其中&#xff0c;r为灰度图像的输入值&#xff08;原来的灰度值&…

<数据集>集装箱缺陷识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;3793张 标注数量(xml文件个数)&#xff1a;3793 标注数量(txt文件个数)&#xff1a;3793 标注类别数&#xff1a;4 标注类别名称&#xff1a;[DAMAGE - DEFRAME, DENT, DAMAGE - RUST, DAMAGE - HOLE] 序号类别名…

高分六号卫星助力农业监测_卫星介绍_论文分享_数据获取

卫星遥感已经成为农业发展的重要支持工具。《“数据要素X”三年行动计划(2024-2026年)》指出,在现代农业交通运输、应急管理等领域鼓励探索利用遥感数据。为什么高分六号会经常应用于农业检测呢&#xff1f;本文将介绍高分六号卫星的农业检测特性、在农业应用中的优势、具体农业…

Video视频抽帧和WebCodecs API视频抽帧介绍

目录 mp4Box抽帧 ffmpeg抽帧 video元素抽帧 WebCodecs 核心API 视频文件是一个容器&#xff0c;里面有很多不同的轨道信息。如&#xff1a;图像、声音、字幕等。而视频图像信息又是由一系列图片序列帧的集合。如10秒时长的视频&#xff0c;假设每秒30帧。那大概有300条图像…

二叉树——9.找树左下角的值

力扣题目链接 给定一个二叉树&#xff0c;在树的最后一行找到最左边的值。 示例&#xff1a; 输出&#xff1a;7 题干很简单&#xff0c;找到树的最后一行&#xff0c;在该行找到最左边的值&#xff0c;结合完整代码进行分析。 完整代码如下&#xff1a; class Solution:d…

Django后台数据获取展示

​ 续接Django REST Framework&#xff0c;使用Vite构建Vue3的前端项目 1.跨域获取后台接口并展示 安装Axios npm install axios --save 前端查看后端所有定义的接口 // 访问后端定义的可视化Api接口文档 http://ip:8000/docs/ // 定义的学生类信息 http://ip:8000/api/v1…

Springboot发邮件如何配置SMTP服务器信息?

Springboot发邮件安全性考虑&#xff1f;如何用Springboot发信&#xff1f; 在 SpringBoot中配置邮件发送功能相对简单&#xff0c;但需要正确设置 SMTP 服务器信息。AokSend将详细介绍如何在 SpringBoot应用程序中配置 SMTP 服务器信息&#xff0c;以实现邮件发送功能。 Spr…

如何构建一个高效的编程学习笔记系统(万字总结)

你是否曾经在编程学习的海洋中迷失方向&#xff1f;是否感觉自己学了很多&#xff0c;却总是记不住关键知识点&#xff1f;别担心&#xff0c;今天我们将一起探索一种革命性的笔记方法&#xff0c;它将彻底改变你的学习体验&#xff01; 目录 引言&#xff1a;为什么我们需要…

鸿蒙(API 12 Beta3版)【本地媒体会话概述】 音视频播控服务

交互过程 本地媒体会话的数据源均在设备本地&#xff0c;交互过程如图所示。 此过程中涉及两大角色&#xff0c;媒体会话提供方和媒体会话控制方。 说明 媒体会话控制方为系统应用&#xff0c;三方应用可以成为媒体会话提供方。 本地媒体会话中&#xff0c;媒体会话提供方通…

[大模型实战] DAMODEL云算力平台部署LLama3.1大语言模型

[大模型实战] DAMODEL云算力平台部署LLama3.1大语言模型 目录 一、LLama3.1二、DAMODEL云算力平台2.1 提供的服务2.1.1 AI训练2.1.2 AI推理2.1.3 高性能计算2.1.4 图像&#xff0f;视频渲染2.1.5 定制化部署 2.2 支持的GPU 三、在DAMODEL部署LLama3.13.1 在DAMODEL创建实例&…

【案例43】打开节点-后台任务日志优化案例

问题现象 通过SPR日志发现 打开节点-后台任务日志节点sql调用严重。 通过nmc查看&#xff0c;后台线程耗时20s &#xff0c;基本都卡在sql层面 一直在执行如下sql selectl.pk_workingtasklog frompub_workingtasklog l inner joinpub_alertregistry ron l.pkregistry r.pk_a…

Black Forest Labs 的 Flux——文本转图像模型的下一个飞跃,它比 Midjourney 更好吗?

一、前言 Black Forest Labs是开创性稳定扩散模型的团队&#xff0c;现已发布Flux——一套最先进的模型&#xff0c;有望重新定义 AI 生成图像的功能。但 Flux 是否真正代表了该领域的飞跃&#xff1f;它与 Midjourney 等行业领导者相比如何&#xff1f;让我们深入探索 Flux 的…

【Kubernetes】Service 概念与实战

Service 概念与实战 1.通过 Service 向外部暴露 Pod2.Service 的多端口设置3.集群内部的 DNS 服务4.无头 Service 在 Kubernetes 中部署的应用可能对应一个或者多个 Pod&#xff0c;而每个 Pod 又具有独立的 IP 地址。Service&#xff08;服务&#xff09;能够为一组功能相同的…

DI (providedIn: XXXModule)

angular版本为^17.3.0&#xff1b; 依赖注入Module 代码结构如下&#xff1a; 点击后为 demo2 works!demo2 providedIn Demo1Module depdemo2 works!demo2 providedIn Demo1Module 打包后大小为 改写为 demo2去掉 imports: [Demo1Module], 打包后大小为 结果比较&#…

DAMA学习笔记(十五)-数据管理组织与角色期望

1.引言 随着数据领域的快速发展&#xff0c;组织需要改进管理和治理数据的方式。当前&#xff0c;大多数组织正面临着越来越多的数据。这些数据格式多样、数量 庞大&#xff0c;并来源于不同的渠道。由于数据数量和种类的增加&#xff0c;加剧了数据 管理的复杂性。与此同时&am…

shiro注解不起作用:shiro进行权限校验时,@RequireRoles(“admin“)注解不起作用的解决方法

今天在写前后端分离项目时&#xff0c;用jwt加shiro进行登录权限校验时&#xff0c;RequireRoles("admin")注解不起作用&#xff0c;记录一下。 前提&#xff1a;数据库里面的user_type代表用户类型 &#xff1a;0普通用户 &#xff1b;1&#xff1a;专家&#xff1…

Introduction to Snapdragon Profiler (Snapdragon 分析器)

Introduction to Snapdragon Profiler {Snapdragon 分析器} 1. Snapdragon Profiler2. Release Notes3. Tools and resourcesReferences Snapdragon Profiler (骁龙分析器) https://www.qualcomm.com/developer/software/snapdragon-profiler Snapdragon Profiler Documentati…

HAProxy基本配置及参数实操

目录 ​编辑什么是负载均衡 为什么用负载均衡 四层和七层的区别 实验环境 实验步骤 webserver上安装nginx 启动nginx 安装haproxy 编辑配置文件 多进程 多线程 SORRY SERVER 访问重定向 maxconne最大可承受连接 socat 工具 常用示例 ha p r ox y 的 算 法 静 …

思科静态路由配置1

#路由协议实现# #任务一静态路由配置1# #1配置Switch-A的名称及其接口IP地址 Switch>enable Switch(config)#hostname Switch-A Switch-A(config)#ip routing Switch-A(config)#int f0/1 Switch-A(config-if)#no switchport Switch-A(config-if)#ip add 192.168.10…

leetcode日记(72)最大矩形

依旧是看了答案才知道大概方法…太难想到了 和上一道题思路相似&#xff01;可以直接调用上题的函数&#xff0c;只不过调用前的准备非常难想到&#xff0c;就是建造形状相同的矩阵&#xff0c;第i行j列的元素是i行中j列前相邻的“1”的个数。 class Solution { public:int m…