Spring进阶 - SpringMVC达成原理(二)DispatcherServlet处理请求的过程

news/2025/10/22 14:39:20/文章来源:https://www.cnblogs.com/slgkaifa/p/19157940

Spring进阶 - SpringMVC达成原理(二)DispatcherServlet处理请求的过程

前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第二篇:DispatcherServlet处理请求的过程的源码解析。

这篇文章能帮你理清楚 JVM、Tomcat、Spring 宏观上的关系。 另外 Servlet ,HttpServlet , ServletRequest, HttpServletRequest 等类,能看到 SpringMVC 对他们的实现与增强,以及SpringMVC处理请求的流程。

回顾整理处理流程

首先让我们整体看一下Spring Web MVC 处理请求的流程:

img

  1. 首先用户发送请求——>DispatcherServlet前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行 处理,作为统一访问点,进行全局的流程控制;
  2. DispatcherServlet——>HandlerMapping, HandlerMapping 将会把请求(如 user/list)映射为 HandlerExecutionChain 对象(包含一 个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
  3. DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器(适配器设计模型,便于调用),从而支持多种类型的处理器, 即适配器设计模式的应用,从而很容易支持很多类型的处理器;
  4. HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法(Controller 方法),完成功能处理;并返回一个ModelAndView 对象, 前后端分离项目返回的是一个 业务对象(如:List );
  5. ModelAndView 的逻辑视图名——> ViewResolver,ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术,**如果是前后端分离项目,此步骤跳过,**没有 ModelAndView 对象,那就没东西解析;
  6. View——>渲染,View 会根据传进来的Model 模型数据进行渲染,此处的Model 实际是一个Map 数据结构,因此很容易支持其他视图技术;
  7. 返回控制权给DispatcherServlet,由DispatcherServlet 返回响应给用户,到此一个流程结束。

JVM 、 Tomcat 、 Spring宏观关系

JVM 是一个进程,Spring boot是一个库(框架),运行在 JVM 之上,tomcat 是内嵌在 Spring Boot 中的,所以本质上就一个 JVM 进程,Spring Boot 和 tomcat 是两个库。

假如没有Spring Boot , 传统的 tomcat 是需要一个 JVM 进程单独启动,不细说。

tomcat 如何提供网络能力呢?这个库为啥能监听网络请求?

本质上是调用了OS操作系统的 API, 一个请求发送到我们的服务器,最先接收到的是网卡,然后操作系统会把请求的数据放到 socket 接收缓冲区,tomcat 具有能够调用操作系统 API 的方法,所以就可以监听操作系统socket缓冲区是否有数据。

1. 用户浏览器发送 HTTP 请求
↓
2. 操作系统网络层接收(TCP/IP)
↓
3. Tomcat 通过 JVM 调用操作系统的网络 API
(通常是通过 Java NIO 或传统的 Socket API)4. Tomcat 解析 HTTP 请求
↓
5. Tomcat 找到对应的 Servlet6. 调用 Servlet 的方法(如 doGet)
↓
7. 返回响应

聊完了这个我们再看看 Servlet , HttpServlet 和 SpringMVC 的关系。

Servlet , HttpServlet 和 SpringMVC

Servlet 是 JavaEE(Jakarta EE)规范里定义的一个接口, 定义了所有 Web 组件(Servlet)的最基本行为 。 比如最基本的生命周期方法:init(), service(), destroy()

HttpServletServlet 接口的一个抽象实现类,理解成对 Servlet 的能力扩展, 专门为 HTTP 协议做了适配 。

Servlet 有一个方法是 Servlet.service(ServletRequest, ServletResponse) ,Servlet 和 ServletRequest 之间有点像调用关系。没有继承关系或者实现关系。

ServletRequest 它是 java 的一个接口, 封装一次请求的数据(不限于 HTTP,可以是任意协议,比如最早还有 FTP、SMTP 的扩展)。

HttpServletRequest 也是 java 的接口, 继承了 ServletRequest 接口,作为它的能力扩展。新增了 HTTP 特有的方法,比如 getMethod() ——> 获取请求方法(GET/POST/PUT/DELETE …) , getCookies(), getSession() 。

以上都是Java规范,接口或者抽象类,Tomcat 对它们都有实现。

tomcat 有 StandardWrapper ,定位和 Servlet 一样,管理容器的生命周期。

tomcat 有 DefaultServlet , 一个具体的 HttpServlet 子类,负责静态资源处理。

tomcat 有 Request 实现了 HttpServletRequest 接口。

关键

已经清晰了 Java 和 Tomcat 的关系,已经完全足够处理请求了,Spring MVC 有什么工作要做呢?

Spring MVC 并没有取代 Servlet,而是构建在 Servlet 之上,提供了一个更强大、更灵活、更易于开发的应用层框架。

我们知道 Spring MVC 核心是 DispatcherServlet这个组件,它本质上是 HttpServlet。也就是说 Spring 提供的一个实现了 HttpServlet 接口的类,跟 tomcat 抢活干?对,前面流程说了 tomcat 会把请求交给 DispatcherServlet 去跑流程,那DispatcherServlet 就要具有处理请求的能力呀,所以必须要实现 HttpServlet 接口。

Spring MVC 只是实现了 HttpServlet 而已?不需要实现 HttpServletRequest 接口吗?

HttpServletRequest 已经被 tomcat 实现了,Spring MVC 没有改动任何 HttpServletRequest ,拿过来直接用,**但是,**Spring MVC 使用了包装器模式对 HttpServletRequest 进行了增强。你使用的是增强版的HttpServletReqeust ,这个增强对开发者来说是透明的,表明上 HttpServletRequest 没有改变。内部有部分简化和增强。

另外Spring MVC 有一个MultipartHttpServletRequest 接口,实现了 HttpServletRequest 接口,让SpringMVC 处理请求时能接收文件。

最后,SpringMVC提供了一个 RequestContextHolder 工具类,鱼总用了多次,将包装后的 Request 对象存放在 **ThreadLocal**(线程上下文) 中,意味着即使在一个没有直接传入 **HttpServletRequest** 对象的深层 Service 方法里,只要你需要,你也可以通过 **RequestContextHolder.getRequestAttributes()** 来获取到当前请求的上下文信息。

下面我们从源码剖析。

doGet入口

我们启动一个 Spring Boot 项目,端口号为 8080 , 当有一个 get 请求(localhost:8080/api/health) ,Spring MVC 处理过程是怎样的?

  1. 用户发起 HTTP GET 请求
  2. Tomcat 接收请求,创建 Request/Response 对象
  3. Tomcat 调用已注册的 DispatcherServlet.doGet() 方方法。 执行权从 Tomcat 转移到 Spring。

我们就从这个 doGet() 方法开始看源码:

首先doGet()

@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
  1. DispatcherServlet.doGet() 调用 processRequest(),执行 Spring 框架通用逻辑,如上下文管理
/**
* Process this request, publishing an event regardless of the outcome.
* <p>The actual event handling is performed by the abstract
* {@link #doService} template method.
*/
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 计算处理请求的时间
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
// 初始化context
initContextHolders(request, localeContext, requestAttributes);
try {
// 看这里
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
// 重置context
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}

最重要的就是调用doService方法,这个方法由DispatchServlet类实现。

SpringMVC 处理请求的流程

请求分发

  1. processRequest() 调用 doService(),控制权从通用框架转交给 MVC 专用,doDispatch方法是真正处理请求的核心方法,流程就到了 Spring MVC, 认真看源码,看看Spring MVC 如何处理请求。
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 {
// 判断是不是文件上传类型的request
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 根据request获取匹配的handler.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据handler获取匹配的handlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 如果handler支持last-modified头处理
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;
}
// 真正handle处理,并返回modelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 通过视图的prefix和postfix获取完整的视图名
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);
}
// 处理handler处理的结果,显然就是对ModelAndView 或者 出现的Excpetion处理
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);
}
}
}
}

映射和适配器处理

对于 42 行真正的handle方法,我们看下其处理流程

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

交给handleInternal方法处理,以RequestMappingHandlerAdapter这个HandlerAdapter中的处理方法为例

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

上面 24 行,打个断点,我们熟悉的 Controller 控制器这这一步触发 ,原来 Spring MVC 中 Handler 处理器概念的技术实现用到了 Controller ,这知识点就接上了我们MVC概念的控制层。控制层会处理数据(Model) , MVC 两个概念都清晰了。当Controller return的时候,会返回 Json 数据给前端,这就属于渲染层了,前后端分离不会真的渲染 HTML 页面给前端了,仅仅是发送JSON数据。

img

来看看controller 具体怎么被执行

然后执行invokeHandlerMethod这个方法,用来对RequestMapping(usercontroller中的list方法)进行处理

**
* Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
* if view resolution is required.
* @since 4.2
* @see #createInvocableHandlerMethod(HandlerMethod)
*/
@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);
// 重要:设置handler(controller#list)方法上的参数,返回值处理,绑定databinder等
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 执行controller中方法
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}

invokeAndHandle交给UserController中具体执行list方法执行

img

后续invoke执行的方法,直接看整个请求流程的调用链即可

img

执行后获得视图和Model

img

视图渲染

还是那句话,前后端分离没有视图渲染这个步骤,这以 JSP 项目为例讲解的完整 MVC 源码。

接下来继续执行processDispatchResult方法,对视图和model(如果有异常则对异常处理)进行处理(显然就是渲染页面了)

/**
* Handle the result of handler selection and handler invocation, which is
* either a ModelAndView or an Exception to be resolved to a 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);
}
}
// 是否需要渲染视图
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);
}
}

接下来显然就是渲染视图了, spring在initStrategies方法中初始化的组件(LocaleResovler等)就派上用场了。

/**
* Render the given ModelAndView.
* <p>This is the last stage in handling a request. It may involve resolving the view by name.
* @param mv the ModelAndView to render
* @param request current HTTP servlet request
* @param response current HTTP servlet response
* @throws ServletException if view is missing or cannot be resolved
* @throws Exception if there's a problem rendering the view
*/
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}

后续就是通过viewResolver进行解析了,这里就不再继续看代码了,上述流程基本上够帮助你构建相关的认知了。

最后无非是返回控制权给DispatcherServlet,由DispatcherServlet 返回响应给用户。

最后的最后我们看下请求的日志:

21:45:53.390 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/011_spring_framework_demo_springmvc_war_exploded/user", parameters={}
21:45:53.400 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to tech.pdai.springframework.springmvc.controller.UserController#list(HttpServletRequest, HttpServletResponse)
22:51:14.504 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.view.JstlView - View name 'userList', model {dateTime=Fri Apr 22 21:45:53 CST 2022, userList=[tech.pdai.springframework.springmvc.entity.User@7b8c8dc]}
22:51:14.550 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.view.JstlView - Forwarding to [/WEB-INF/views/userList.jsp]
22:51:44.395 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK

参考文章

https://pdai.tech/md/spring/spring-x-framework-springmvc-source-2.html

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

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

相关文章

2025多校冲刺CSP模拟赛7

2025多校冲刺CSP模拟赛7 不是你怎么还有加赛?ys A. gcd&xor (gcdxor) 转化为外层枚举 \(\gcd\),内层枚举 \(i,j\),打表即可。可以发现规律,是调和级数做法,时间复杂度大约 \(O(1.5 \times 10^8)\)。 Code: #…

视频汇聚平台EasyCVR级联播放偶发失败排查:TCP主动模式下的3秒超时响应差

在视频监控平台的级联场景中,“有时能播、有时不能播”的偶发问题往往比必现问题更难排查。最近我们收到用户反馈:EasyCVR作为上级平台,请求播放下级级联的同一路视频时,出现间歇性播放失败的情况——同一通道有时…

redis 5.0单机部署

环境:OS:Centos 7redis:5.0.14问题1:You need tcl 8.5 or newer in order to run the Redis testrpm -qa | grep tcl解决办法:yum install tcl问题2: make test 报错误!!! WARNING The following tests failed:*** [e…

企业微信ipad协议,标准化接口服务解决方案

企业微信ipad协议,标准化接口服务解决方案企业微信 iPad 协议是一种基于企业微信 iPad 版本的智能接口服务解决方案,通过逆向工程技术将 iPad 客户端的私有二进制接口转化为可编程的API通信协议接口,模拟 iPad 客户端…

2025年DevOps平台全景观察:本土化与全球化双轨并行下的企业选择

2025年DevOps平台全景观察:本土化与全球化双轨并行下的企业选择 数字化转型浪潮席卷全球,企业研发效能提升已成为核心竞争力。在这样的大背景下,DevOps平台作为连接开发与运维的关键纽带,正经历着前所未有的变革与…

Python实现基于SAO-Transformer-LSTM雪消融优化算法(SAO)优化Transformer-LSTM组合模型进行多变量回归预测的详细项目实例 - 详解

Python实现基于SAO-Transformer-LSTM雪消融优化算法(SAO)优化Transformer-LSTM组合模型进行多变量回归预测的详细项目实例 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: au…

2025 年最新推荐!国内污水处理设备优质厂家排行榜,助力企业精准选优质设备

当前,环保政策日趋严格,污水处理需求持续攀升,但市场上污水处理设备厂家良莠不齐,部分厂家技术落后、设备效率低,难以满足企业达标排放需求,还可能因售后缺失导致设备故障后无法及时运维,给企业带来经济损失与环…

2025年模内注塑标杆厂家:腾达鑫电子,IML|IMD|IMR|IMP 定制新标准

在 3C 电子、家电行业外观装饰技术迭代升级的 2025 年,深圳市腾达鑫电子科技有限公司凭借对模内注塑全工艺赛道的深耕布局与技术突破,成为众多知名企业供应链中的 “优选合作伙伴”。自成立以来,公司始终以 “技术赋…

zlog3

用户消费行为数据分析 需求分析 1、数据收集 收集大量的用户消费数据。 2、数据清洗与预处理 收集到的数据可能存在错误、缺失或重复项,需要进行数据清洗和预处理,确保数据的准确性和完整性,使其适合后续的工作。 3…

信息熵的特征选择算法MATLAB实现

信息熵的特征选择算法MATLAB实现。信息熵是衡量特征重要性的强大工具,特别适用于高维数据降维。 1. 信息熵理论基础 1.1 基本概念 信息熵定义: H(X) = -Σ P(x_i) log₂ P(x_i)条件熵: H(Y|X) = -Σ P(x_i) Σ P(y_…

Qoder 上线提示词增强功能,将开发者从“提示词”的负担中解放出来

在 Agentic Coding 时代,我们常常面临一个核心痛点:想要获得顶尖的回答,你必须先提出一个顶尖的问题。 对于开发者而言,这意味着需要花费大量精力去构思、打磨给 AI 的“提示词”。在 Agentic Coding 时代,我们常…

2025 文审礼品机源头厂家最新推荐榜:奔奔游乐居首,合规资质 + 实力口碑双保障权威排行

引言 随着文旅产业与商业娱乐融合加速,文审礼品机成为商场、电玩城等场所引流增收的核心设备,但市场选择难题日益凸显。部分厂家缺乏文审资质,导致设备无法合法流通,给经营者埋下法律隐患;多数产品同质化严重,功…

数字商品服务助力开发者降本增效,加速数字商品商业变现

在数字内容消费快速增长的背景下,开发者面临应用内数字商品维护效率低、多端适配困难、交易合规成本高、用户付费率和留存低等痛点,而用户则遭遇商品交易流程繁琐、权益管理混乱等问题。 HarmonyOS SDK应用市场服务(…

系统建设

系统建设2025-10-22 14:20 luoguoling 阅读(0) 评论(0) 收藏 举报https://mp.weixin.qq.com/s/cW_MEyrrL1Sq0dumw6xRBw

Python-配置PyCharm使用正确的Python解释器

方法一:使用系统Python解释器打开PyCharm进入 File → Settings → Project → Python Interpreter点击右侧的 Add Interpreter,选择 Add Local Interpreter选择 System Interpreter在解释器路径中,选择你安装PyTor…

pytorch第66页

点击查看代码 import torch from torch import optim, nn from torchvision import datasets, transforms from torch.utils.data import DataLoader import torch.nn.functional as F import numpy as np from sklear…

Navicat Premium 17 官方版下载安装教程|支持MySQL、PostgreSQL、MongoDB等数据库

Navicat Premium是一款功能强大的数据库管理和开发工具,专为PC电脑端设计。它支持多种数据库类型,包括MySQL、SQLite、SQL Server、Oracle、PostgreSQL、MariaDB和MongoDB,让用户能够轻松管理这些不同类型的数据库。…

有什么指标可以判断手机是否降频

1)有什么指标可以判断手机是否降频2)关于降低动画浮点数精度的问这是第449篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地掌握和学习。 UWA社区主页:c…

实用指南:Linux内核kallsyms符号压缩与解压机制

实用指南:Linux内核kallsyms符号压缩与解压机制pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", …