当前位置: 首页 > news >正文

SpringMVC底层原理源码解析

SpringMVC的作用毋庸置疑,虽然我们现在都是用SpringBoot,但是SpringBoot中仍然是在使用SpringMVC来处理请求。

我们在使用SpringMVC时,传统的方式是通过定义web.xml,比如:

<web-app><servlet><servlet-name>app</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>app</servlet-name><url-pattern>/app/*</url-pattern></servlet-mapping></web-app>

我们只要定义这样的一个web.xml,然后启动Tomcat,那么我们就能正常使用SpringMVC了。

SpringMVC中,最为核心的就是DispatcherServlet,在启动Tomcat的过程中:

  1. Tomcat会先创建DispatcherServlet对象
  2. 然后调用DispatcherServlet对象的init()

而在init()方法中,会创建一个Spring容器,并且添加一个ContextRefreshListener监听器,该监听器会监听ContextRefreshedEvent事件(Spring容器启动完成后就会发布这个事件),也就是说Spring容器启动完成后,就会执行ContextRefreshListener中的onApplicationEvent()方法,从而最终会执行DispatcherServlet中的initStrategies(),这个方法中会初始化更多内容:

protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);
}

其中最为核心的就是HandlerMapping和HandlerAdapter。

什么是Handler?

Handler表示请求处理器,在SpringMVC中有四种Handler:

  1. 实现了Controller接口的Bean对象
  2. 实现了HttpRequestHandler接口的Bean对象
  3. 添加了@RequestMapping注解的方法
  4. 一个HandlerFunction对象

比如实现了Controller接口的Bean对象:

@Component("/test2")
public class ControllerController implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {ModelAndView mav = new ModelAndView(new MappingJackson2JsonView());mav.addObject("result", "{}");return mav;}
}

实现了HttpRequestHandler接口的Bean对象:

@Component("/test3")
public class HttpRequestHandlerController implements HttpRequestHandler {@Overridepublic void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {JSONObject jsonObject = new JSONObject();jsonObject.put("result", "{}");response.getWriter().write(jsonObject.toJSONString());}
}

添加了@RequestMapping注解的方法:

public class Controller {@RequestMapping(method = RequestMethod.GET, path = "/test")@ResponseBodypublic Object controller() {Map<Object, String> result = new HashMap<>(1);result.put("result", "{}");return result;}}

一个HandlerFunction对象(以下代码中有两个):

public class AppConfig {@Beanpublic RouterFunction<ServerResponse> person() {JSONObject jsonObject = new JSONObject();jsonObject.put("result", "{}");return route().GET("test4", request -> ServerResponse.status(HttpStatus.OK).body(jsonObject.toJSONString())).POST("test4", request -> ServerResponse.status(HttpStatus.OK).body(jsonObject.toJSONString())).build();}}

什么是HandlerMapping?

HandlerMapping负责去寻找Handler,并且保存路径和Handler之间的映射关系。

因为有不同类型的Handler,所以在SpringMVC中会由不同的HandlerMapping来负责寻找Handler,比如:

  1. BeanNameUrlHandlerMapping:负责Controller接口和HttpRequestHandler接口
  2. RequestMappingHandlerMapping:负责@RequestMapping的方法
  3. RouterFunctionMapping:负责RouterFunction以及其中的HandlerFunction

BeanNameUrlHandlerMapping的寻找流程:

  1. 找出Spring容器中所有的beanName
  2. 判断beanName是不是以“/”开头
  3. 如果是,则把它当作一个Handler,并把beanName作为key,bean对象作为value存入handlerMap中
  4. handlerMap就是一个Map

RequestMappingHandlerMapping的寻找流程:

  1. 找出Spring容器中所有beanType
  2. 判断beanType是不是有@Controller注解,或者是不是有@RequestMapping注解
  3. 判断成功则继续找beanType中加了@RequestMapping的Method
  4. 并解析@RequestMapping中的内容,比如method、path,封装为一个RequestMappingInfo对象
  5. 最后把RequestMappingInfo对象做为key,Method对象封装为HandlerMethod对象后作为value,存入registry中
  6. registry就是一个Map

RouterFunctionMapping的寻找流程会有些区别,但是大体是差不多的,相当于是一个path对应一个HandlerFunction。

各个HandlerMapping除开负责寻找Handler并记录映射关系之外,自然还需要根据请求路径找到对应的Handler,在源码中这三个HandlerMapping有一个共同的父类AbstractHandlerMapping

AbstractHandlerMapping实现了HandlerMapping接口,并实现了getHandler(HttpServletRequest request)方法。

AbstractHandlerMapping会负责调用子类的getHandlerInternal(HttpServletRequest request)方法从而找到请求对应的Handler,然后AbstractHandlerMapping负责将Handler和应用中所配置的HandlerInterceptor整合成为一个HandlerExecutionChain对象。

所以寻找Handler的源码实现在各个HandlerMapping子类中的getHandlerInternal()中,根据请求路径找到Handler的过程并不复杂,因为路径和Handler的映射关系已经存在Map中了。

比较困难的点在于,当DispatcherServlet接收到一个请求时,该利用哪个HandlerMapping来寻找Handler呢?看源码:

很简单,就是遍历,找到就返回,默认顺序为:

所以BeanNameUrlHandlerMapping的优先级最高,比如:

如果请求路径都是/test,但是最终是Controller接口的会生效。

什么是HandlerAdapter?

找到了Handler之后,接下来就该去执行了,比如执行下面这个test()

但是由于有不同种类的Handler,所以执行方式是不一样的,再来总结一下Handler的类型:

  1. 实现了Controller接口的Bean对象,执行的是Bean对象中的handleRequest()
  2. 实现了HttpRequestHandler接口的Bean对象,执行的是Bean对象中的handleRequest()
  3. 添加了@RequestMapping注解的方法,具体为一个HandlerMethod,执行的就是当前加了注解的方法
  4. 一个HandlerFunction对象,执行的是HandlerFunction对象中的handle()

所以,按逻辑来说,找到Handler之后,我们得判断它的类型,比如代码可能是这样的:

Object handler = mappedHandler.getHandler();
if (handler instanceof Controller) {((Controller)handler).handleRequest(request, response);
} else if (handler instanceof HttpRequestHandler) {((HttpRequestHandler)handler).handleRequest(request, response);
} else if (handler instanceof HandlerMethod) {((HandlerMethod)handler).getMethod().invoke(...);
} else if (handler instanceof HandlerFunction) {((HandlerFunction)handler).handle(...);
}

但是SpringMVC并不是这么写的,还是采用的适配模式,把不同种类的Handler适配成一个HandlerAdapter,后续再执行HandlerAdapter的handle()方法就能执行不同种类Hanlder对应的方法。

针对不同的Handler,会有不同的适配器:

  1. HttpRequestHandlerAdapter
  2. SimpleControllerHandlerAdapter
  3. RequestMappingHandlerAdapter
  4. HandlerFunctionAdapter

适配逻辑为:

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

传入handler,遍历上面四个Adapter,谁支持就返回谁,比如判断的代码依次为:

public boolean supports(Object handler) {return (handler instanceof HttpRequestHandler);
}public boolean supports(Object handler) {return (handler instanceof Controller);
}public final boolean supports(Object handler) {return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}public boolean supports(Object handler) {return handler instanceof HandlerFunction;
}

根据Handler适配出了对应的HandlerAdapter后,就执行具体HandlerAdapter对象的handle()方法了,比如:

HttpRequestHandlerAdapter的handle():

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {((HttpRequestHandler) handler).handleRequest(request, response);return null;
}

SimpleControllerHandlerAdapter的handle():

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return ((Controller) handler).handleRequest(request, response);
}

HandlerFunctionAdapter的handle():

HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
serverResponse = handlerFunction.handle(serverRequest);

因为这三个接收的直接就是Requeset对象,不用SpringMVC做额外的解析,所以比较简单,比较复杂的是RequestMappingHandlerAdapter,它执行的是加了@RequestMapping的方法,而这种方法的写法可以是多种多样,SpringMVC需要根据方法的定义去解析Request对象,从请求中获取出对应的数据然后传递给方法,并执行。

@RequestMapping方法参数解析
当SpringMVC接收到请求,并找到了对应的Method之后,就要执行该方法了,不过在执行之前需要根据方法定义的参数信息,从请求中获取出对应的数据,然后将数据传给方法并执行。

一个HttpServletRequest通常有:

  1. request parameter
  2. request attribute
  3. request session
  4. reqeust header
  5. reqeust body

比如如下几个方法:

public String test(String username) {return "test";
}

表示要从request parameter中获取key为username的value

public String test(@RequestParam("uname") String username) {return "test";
}

表示要从request attribute中获取key为username的value

public String test(@RequestAttribute String username) {return "test";
}

表示要从request session中获取key为username的value

public String test(@SessionAttribute String username) {return "test";
}

表示要从request header中获取key为username的value

public String test(@RequestHeader String username) {return "test";
}

表示获取整个请求体

public String test(@RequestBody String username) {return "test";
}

所以,我们发现SpringMVC要去解析方法参数,看该参数到底是要获取请求中的哪些信息。

而这个过程,源码中是通过HandlerMethodArgumentResolver来实现的,比如:

  1. RequestParamMethodArgumentResolver:负责处理@RequestParam
  2. RequestHeaderMethodArgumentResolver:负责处理@RequestHeader
  3. SessionAttributeMethodArgumentResolver:负责处理@SessionAttribute
  4. RequestAttributeMethodArgumentResolver:负责处理@RequestAttribute
  5. RequestResponseBodyMethodProcessor:负责处理@RequestBody
  6. 还有很多其他的...

而在判断某个参数该由哪个HandlerMethodArgumentResolver处理时,也是很粗暴:

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);if (result == null) {for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {if (resolver.supportsParameter(parameter)) {result = resolver;this.argumentResolverCache.put(parameter, result);break;}}}return result;}

就是遍历所有的HandlerMethodArgumentResolver,哪个能支持处理当前这个参数就由哪个处理。

比如:

@RequestMapping(method = RequestMethod.GET, path = "/test")
@ResponseBody
public String test(@RequestParam @SessionAttribute String username) {System.out.println(username);return "test";
}

以上代码的username将对应RequestParam中的username,而不是session中的,因为在源码中RequestParamMethodArgumentResolver更靠前。

当然HandlerMethodArgumentResolver也会负责从request中获取对应的数据,对应的是resolveArgument()方法。

比如RequestParamMethodArgumentResolver:

protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);if (servletRequest != null) {Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {return mpArg;}}Object arg = null;MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);if (multipartRequest != null) {List<MultipartFile> files = multipartRequest.getFiles(name);if (!files.isEmpty()) {arg = (files.size() == 1 ? files.get(0) : files);}}if (arg == null) {String[] paramValues = request.getParameterValues(name);if (paramValues != null) {arg = (paramValues.length == 1 ? paramValues[0] : paramValues);}}return arg;
}

核心是:

if (arg == null) {String[] paramValues = request.getParameterValues(name);if (paramValues != null) {arg = (paramValues.length == 1 ? paramValues[0] : paramValues);}
}

按同样的思路,可以找到方法中每个参数所要求的值,从而执行方法,得到方法的返回值。

@RequestMapping方法返回值解析

而方法返回值,也会分为不同的情况。比如有没有加@ResponseBody注解,如果方法返回一个String:

  1. 加了@ResponseBody注解:表示直接将这个String返回给浏览器
  2. 没有加@ResponseBody注解:表示应该根据这个String找到对应的页面,把页面返回给浏览器

在SpringMVC中,会利用HandlerMethodReturnValueHandler来处理返回值:

  1. RequestResponseBodyMethodProcessor:处理加了@ResponseBody注解的情况
  2. ViewNameMethodReturnValueHandler:处理没有加@ResponseBody注解并且返回值类型为String的情况
  3. ModelMethodProcessor:处理返回值是Model类型的情况
  4. 还有很多其他的...

我们这里只讲RequestResponseBodyMethodProcessor,因为它会处理加了@ResponseBody注解的情况,也是目前我们用得最多的情况。

RequestResponseBodyMethodProcessor相当于会把方法返回的对象直接响应给浏览器,如果返回的是一个字符串,那么好说,直接把字符串响应给浏览器,那如果返回的是一个Map呢?是一个User对象呢?该怎么把这些复杂对象响应给浏览器呢?

处理这块,SpringMVC会利用HttpMessageConverter来处理,比如默认情况下,SpringMVC会有4个HttpMessageConverter:

  1. ByteArrayHttpMessageConverter:处理返回值为字节数组的情况,把字节数组返回给浏览器
  2. StringHttpMessageConverter:处理返回值为字符串的情况,把字符串按指定的编码序列号后返回给浏览器
  3. SourceHttpMessageConverter:处理返回值为XML对象的情况,比如把DOMSource对象返回给浏览器
  4. AllEncompassingFormHttpMessageConverter:处理返回值为MultiValueMap对象的情况

StringHttpMessageConverter的源码也比较简单:

protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {HttpHeaders headers = outputMessage.getHeaders();if (this.writeAcceptCharset && headers.get(HttpHeaders.ACCEPT_CHARSET) == null) {headers.setAcceptCharset(getAcceptedCharsets());}Charset charset = getContentTypeCharset(headers.getContentType());StreamUtils.copy(str, charset, outputMessage.getBody());
}

先看有没有设置Content-Type,如果没有设置则取默认的,默认为ISO-8859-1,所以默认情况下返回中文会乱码,可以通过以下来中方式来解决:

@RequestMapping(method = RequestMethod.GET, path = "/test", produces = {"application/json;charset=UTF-8"})
@ResponseBody
public String test() {return "test";
}
@ComponentScan
@Configuration
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {StringHttpMessageConverter messageConverter = new StringHttpMessageConverter();messageConverter.setDefaultCharset(StandardCharsets.UTF_8);converters.add(messageConverter);}
}

不过以上四个Converter是不能处理Map对象或User对象的,所以如果返回的是Map或User对象,那么得单独配置一个Converter,比如MappingJackson2HttpMessageConverter,这个Converter比较强大,能把String、Map、User对象等等都能转化成JSON格式。

@ComponentScan
@Configuration
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();messageConverter.setDefaultCharset(StandardCharsets.UTF_8);converters.add(messageConverter);}
}

具体转化的逻辑就是Jackson2的转化逻辑。

相关文章:

SpringMVC底层原理源码解析

SpringMVC的作用毋庸置疑&#xff0c;虽然我们现在都是用SpringBoot&#xff0c;但是SpringBoot中仍然是在使用SpringMVC来处理请求。 我们在使用SpringMVC时&#xff0c;传统的方式是通过定义web.xml&#xff0c;比如&#xff1a; <web-app><servlet><servle…...

【CSS系列】第八章 · CSS浮动

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…...

janus videoroom 对接freeswitch conference 篇1

janus videoroom 实时性非常好&#xff0c; freeswitch conference的功能也很多 &#xff0c;有没办法集成到一块呢 让很多sip 视频终端也能显示到videoroom 里面&#xff0c; 实现方式要不两种 1.改源码实现 &#xff08;本文忽略 难度高&#xff09; 2.找一个videoroom管…...

cs109-energy+哈佛大学能源探索项目 Part-2.1(Data Wrangling)

博主前期相关的博客见下&#xff1a; cs109-energy哈佛大学能源探索项目 Part-1&#xff08;项目背景&#xff09; 这次主要讲数据的整理。 Data Wrangling 数据整理 在哈佛的一些大型建筑中&#xff0c;有三种类型的能源消耗&#xff0c;电力&#xff0c;冷冻水和蒸汽。 冷冻…...

__101对称二叉树------进阶:你可以运用递归和迭代两种方法解决这个问题吗?---本题还没用【迭代】去实现

101对称二叉树 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 101. 对称二叉树 https://leetcode.cn/problems/symmetric-tree/ 完成情况&#xff1a; 解题思路&#xff1a; 递归的难点在于&#xff1a;找到可以…...

怎么取消只读模式?硬盘进入只读模式怎么办?

案例&#xff1a;电脑磁盘数据不能修改怎么办&#xff1f; 【今天工作的时候&#xff0c;我想把最近的更新的资料同步到电脑上的工作磁盘&#xff0c;但是发现我无法进行此操作&#xff0c;也不能对磁盘里的数据进行改动。有没有小伙伴知道这是怎么一回事&#xff1f;】 在使…...

如何使用Java生成Web项目验证码

使用Java编写Web项目验证码 验证码是Web开发中常用的一种验证方式,可以防止机器恶意攻击。本文将介绍如何使用Java编写Web项目验证码,包括步骤、示例和测试。 步骤 1. 添加依赖 首先需要在项目中添加以下依赖: <dependency><groupId>com.google.code.kaptc…...

【读书笔记】《亲密关系》

作者&#xff1a;美国的罗兰米勒 刚拿到这本书的时候&#xff0c;就被最后将近100页的参考文献折服了&#xff0c;让我认为这本书极具专业性。 作者使用了14章&#xff0c;从人与人之间是如何相互吸引的&#xff0c;讲到如何相处与沟通&#xff0c;后又讲到如何面对冲突与解决矛…...

面试季,真的太狠了...

金三银四面试季的复盘&#xff0c;真的太狠了… 面试感受 先说一个字 是真的 “ 累 ” 安排的太满的后果可能就是一天只吃一顿饭&#xff0c;一直奔波在路上 不扯这个了&#xff0c;给大家说说面试吧&#xff0c;我工作大概两年多的时间&#xff0c;大家可以参考下 在整个面…...

2023年十大最佳黑客工具!

​用心做分享&#xff0c;只为给您最好的学习教程 如果您觉得文章不错&#xff0c;欢迎持续学习 在今年根据实际情况&#xff0c;结合全球黑客共同推崇&#xff0c;选出了2023年十大最佳黑客工具。 每一年&#xff0c;我都会持续更新&#xff0c;并根据实际现实情况随时更改…...

每日练习---C语言

目录 前言&#xff1a; 1.打印菱形 1.1补充练习 2.打印水仙花 2.1补充训练 前言&#xff1a; 记录博主做题的收获&#xff0c;以及提升自己的代码能力&#xff0c;今天写的题目是&#xff1a;打印菱形、打印水仙花数。 1.打印菱形 我们先看到牛客网的题&#xff1a;OJ链…...

边缘计算如何推动物联网的发展

随着物联网&#xff08;IoT&#xff09;的快速发展&#xff0c;物联网设备数量呈现爆炸性增长&#xff0c;这给网络带来了巨大的压力和挑战。边缘计算作为一种新兴的计算模式&#xff0c;旨在解决数据处理和通信在网络传输中的延迟和带宽限制问题&#xff0c;从而提高数据处理效…...

第五章 栈与队列

目录 一、用栈实现队列二、用队列实现栈三、有效的括号四、删除字符串中的所有相邻重复项五、逆波兰表达式求值六、滑动窗口最大值七、前 K 个高频元素 一、用栈实现队列 Leetcode 232 class MyQueue { public:stack<int> in, out;MyQueue() {}void push(int x) {in.pu…...

PyQt5桌面应用开发(16):定制化控件-QPainter绘图

本文目录 PyQt5桌面应用系列画画图&#xff0c;喝喝茶QPainter和QPixmapQPixmapQPainter绘制事件 一个魔改的QLabelCanvas类主窗口主程序&#xff1a; 总结 PyQt5桌面应用系列 PyQt5桌面应用开发&#xff08;1&#xff09;&#xff1a;需求分析 PyQt5桌面应用开发&#xff08;2…...

spring5源码篇(9)——mybatis-spring整合原理

spring-framework 版本&#xff1a;v5.3.19 spring和mybatis的整合无非主要就是以下几个方面&#xff1a; 1、SqlSessionFactory怎么注入&#xff1f; 2、Mapper代理怎么注入&#xff1f; 3、为什么要接管mybatis事务&#xff1f; 文章目录 一、SqlSessionFactory怎么注入SqlSe…...

为什么需要防雷接地,防雷接地的作用是什么

为什么需要电气接地&#xff1f; 您是否曾经在工作条件下使用任何电器时接触过电击&#xff1f;几乎每个人的答案都是肯定的&#xff0c;有时这些电击是轻微的&#xff0c;但有时会对电气和电子设备造成损坏&#xff0c;并可能危及生命。为防止对人的生命和电器造成任何损害&a…...

如何应用金字塔模型提高结构化表达能力

看一下结构化表达的定义&#xff1a; 结构化表达&#xff1a;是基于结构化思维&#xff0c;理清事物整理与部分之间关系、换位思考后&#xff0c;进行简洁、清晰和有信服力的表达&#xff0c;是一种让受众听得明白、记得清楚、产生认同的精益沟通方式。 结构化表达的基本原则是…...

2023年系统分析师考前几页纸

企业战略规划是用机会和威胁评价现在和未来的环境,用优势和劣势评价企业现状,进而选择和确定企业的总体和长远目标,制定和抉择实现目标的行动方案。信息系统战略规划关注的是如何通过该信息系统来支撑业务流程的运作,进而实现企业的关键业务目标,其重点在于对信息系统远景…...

openwrt-安装NGINX

openwrt-安装NGINX 介绍 OpenWrt 是一个用于嵌入式设备的开源操作系统。它基于 Linux 内核&#xff0c;并且主要被设计用于路由器和网络设备。 OpenWrt 的主要特点包括&#xff1a; 完全可定制&#xff1a;OpenWrt 提供了一个完全可写的文件系统&#xff0c;用户可以自定义设…...

Linux安装MongoDB数据库并内网穿透在外远程访问

文章目录 前言1.配置Mongodb源2.安装MongoDB数据库3.局域网连接测试4.安装cpolar内网穿透5.配置公网访问地址6.公网远程连接7.固定连接公网地址8.使用固定公网地址连接 转发自CSDN cpolarlisa的文章&#xff1a;Linux服务器安装部署MongoDB数据库 - 无公网IP远程连接「内网穿透…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...