Spring Boot 定义接口的方法是否可以声明为 Private?

Springboot 最细节全面的接口传参接参介绍,总有你喜欢的一种方式 这篇里面对每种传参接参方式都会举出较多的例子,不多说,入正题: @PathVariable 一 @GetMapping("/getId/{id}") public String pathVariableTest(@PathVariable Integer id) { return "id: "+id; } 二 @GetMappin... 阅读详情

我们在 Controller 中定义接口的时候,一般都是像下面这样:

<pre class="prettyprint hljs dart" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@GetMapping("/01")
public String hello(Map<String,Object> map) {
    map.put("name", "javaboy");
    return "forward:/index";
}

估计很少有人会把接口方法定义成 private 的吧?那我们不禁要问,如果非要定义成 private 的方法,那能运行起来吗?

带着这个疑问,我们开始今天的源码解读~

在我们使用 Spring Boot 的时候,经常会看到 HandlerMethod 这个类型,例如我们在定义拦截器的时候,如果拦截目标是一个方法,则 preHandle 的第三个参数就是 HandlerMethod:

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Component
public class IdempotentInterceptor implements HandlerInterceptor {
    @Autowired
    TokenService tokenService;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        //省略...
        return true;
    }
    //...
}

我们在阅读 SpringMVC 源码的时候,也会反复看到这个 HandlerMethod,那么它到底是什么意思?今天我想和小伙伴们捋一捋这个问题,把这个问题搞清楚了,前面的问题大家也就懂了。

1.概览

可以看到,HandlerMethod 体系下的类并不多:

HandlerMethod

封装 Handler 和具体处理请求的 Method。

InvocableHandlerMethod

在 HandlerMethod 的基础上增加了调用的功能。

ServletInvocableHandlerMethod

在 InvocableHandlerMethod 的基础上增了对 @ResponseStatus 注解的支持、增加了对返回值的处理。

ConcurrentResultHandlerMethod

在 ServletInvocableHandlerMethod 的基础上,增加了对异步结果的处理。

基本上就是这四个,接下来就来详细说一说这四个组件。

2.HandlerMethod

2.1 bridgedMethod

在正式开始介绍 HandlerMethod 之前,想先和大家聊聊 bridgedMethod,因为在 HandlerMethod 中将会涉及到这个东西,而有的小伙伴可能还没听说过 bridgedMethod,因此在这里做一个简单介绍。

首先考考大家,下面这段代码编译会报错吗?

<pre class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public interface Animal<T> {
    void eat(T t);
}
public class Cat implements Animal<String> {
    @Override
    public void eat(String s) {
        System.out.println("cat eat " + s);
    }
}
public class Demo01 {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.eat(new Object());
    }
}

首先我们定义了一个 Animal 接口,里边定义了一个 eat 方法,同时声明了一个泛型。Cat 实现了 Animal 接口,将泛型也定义为了 String。当我调用的时候,声明类型是 Animal,实际类型是 Cat,这个时候调 eat 方法传入了 Object 对象大家猜猜会怎么样?如果调用 eat 方法时传入的是 String 类型那就肯定没问题,但如果不是 String 呢?

先说结论:编译没问题,运行报错。

如果小伙伴们在自己电脑上写出上面这段代码,你会发现这样一个问题,开发工具中提示的参数类型竟然是 Object,以IDEA 为例,如下:

大家看到,在写代码的时候,开发工具会给我提示,这个参数类型是 Object,有的小伙伴会觉得奇怪,明明是泛型,怎么变成 Object 了?

我们可以通过反射查看 Cat 类中到底有哪些方法,代码如下:

<pre class="prettyprint hljs swift" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public class Demo01 {
    public static void main(String[] args) {
        Method[] methods = Cat.class.getMethods();
        for (Method method : methods) {
            String name = method.getName();
            Class<?>[] parameterTypes = method.getParameterTypes();
            System.out.println(name+"("+ Arrays.toString(parameterTypes) +")");
        }
    }
}

运行结果如下:

 

 

可以看到,在实际运行过程中,竟然有两个 eat 方法,一个的参数为 String 类型,另一个参数为 Object 类型,这是怎么回事呢?

这个参数类型为 Object 的方法其实是 Java 虚拟机在运行时创建出来的,这个方法就是我们所说的 bridge method。本节的小标题叫做 bridgedMethod,这是 HandlerMethod 源码中的变量名,bridge 结尾多了一个 d,含义变成了被 bridge 的方法,也就是参数为 String 的原方法,大家在接下来的源码中看到了 bridgedMethod 就知道这表示参数类型不变的原方法。

2.2 HandlerMethod 介绍

接下来我们来简单看下 HandlerMethod。

在我们前面分析 HandlerMapping 的时候(参见:),里边有涉及到 HandlerMethod,创建 HandlerMethod 的入口方法是 createWithResolvedBean,因此这里我们就从该方法开始看起:

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public HandlerMethod createWithResolvedBean() {
 Object handler = this.bean;
 if (this.bean instanceof String) {
  String beanName = (String) this.bean;
  handler = this.beanFactory.getBean(beanName);
 }
 return new HandlerMethod(this, handler);
}

这个方法主要是确认了一下 handler 的类型,如果 handler 是 String 类型,则根据 beanName 从 Spring 容器中重新查找到 handler 对象,然后构建 HandlerMethod:

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
 this.bean = handler;
 this.beanFactory = handlerMethod.beanFactory;
 this.beanType = handlerMethod.beanType;
 this.method = handlerMethod.method;
 this.bridgedMethod = handlerMethod.bridgedMethod;
 this.parameters = handlerMethod.parameters;
 this.responseStatus = handlerMethod.responseStatus;
 this.responseStatusReason = handlerMethod.responseStatusReason;
 this.resolvedFromHandlerMethod = handlerMethod;
 this.description = handlerMethod.description;
}

这里的参数都比较简单,没啥好说的,唯一值得介绍的地方有两个:parameters 和 responseStatus。

parameters

parameters 实际上就是方法参数,对应的类型是 MethodParameter,这个类的源码我这里就不贴出来了,主要和大家说一下封装的内容包括:参数的序号(parameterIndex),参数嵌套级别(nestingLevel),参数类型(parameterType),参数的注解(parameterAnnotations),参数名称查找器(parameterNameDiscoverer),参数名称(parameterName)等。

HandlerMethod 中还提供了两个内部类来封装 MethodParameter,分别是:

  • HandlerMethodParameter:这个封装方法调用的参数。
  • ReturnValueMethodParameter:这个继承自 HandlerMethodParameter,它封装了方法的返回值,返回值里边的 parameterIndex 是 -1。

注意,这两者中的 method 都是 bridgedMethod。

responseStatus

这个主要是处理方法的 @ResponseStatus 注解,这个注解用来描述方法的响应状态码,使用方式像下面这样:

<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@GetMapping("/04")
@ResponseBody
@ResponseStatus(code = HttpStatus.OK)
public void hello4(@SessionAttribute("name") String name) {
    System.out.println("name = " + name);
}

从这段代码中大家可以看到,其实 @ResponseStatus 注解灵活性很差,不实用,当我们定义一个接口的时候,很难预知到该接口的响应状态码是 200。

在 handlerMethod 中,在调用其构造方法的时候,都会调用 evaluateResponseStatus 方法处理 @ResponseStatus 注解,如下:

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">private void evaluateResponseStatus() {
 ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class);
 if (annotation == null) {
  annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
 }
 if (annotation != null) {
  this.responseStatus = annotation.code();
  this.responseStatusReason = annotation.reason();
 }
}

可以看到,这段代码也比较简单,找到注解,把里边的值解析出来,赋值给相应的变量。

这下小伙伴们应该明白了 HandlerMethod 大概是个怎么回事。

3.InvocableHandlerMethod

看名字就知道,InvocableHandlerMethod 可以调用 HandlerMethod 中的具体方法,也就是 bridgedMethod。我们先来看下 InvocableHandlerMethod 中声明的属性:

<pre class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
@Nullable
private WebDataBinderFactory dataBinderFactory;

主要就是这三个属性:

  • resolvers:
  • parameterNameDiscoverer:这个用来获取参数名称,在 MethodParameter 中会用到。
  • dataBinderFactory:这个用来创建 WebDataBinder,在参数解析器中会用到。

具体的请求调用方法是 invokeForRequest,我们一起来看下:

<pre class="prettyprint hljs dart" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
  Object... providedArgs) throws Exception {
 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
 return doInvoke(args);
}
@Nullable
protected Object doInvoke(Object... args) throws Exception {
 Method method = getBridgedMethod();
 ReflectionUtils.makeAccessible(method);
 try {
  if (KotlinDetector.isSuspendingFunction(method)) {
   return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
  }
  return method.invoke(getBean(), args);
 }
 catch (InvocationTargetException ex) {
  // 省略 ...
 }
}

首先调用 getMethodArgumentValues 方法按顺序获取到所有参数的值,这些参数值组成一个数组,然后调用 doInvoke 方法执行,在 doInvoke 方法中,首先获取到 bridgedMethod,并设置其可见(意味着我们在 Controller 中定义的接口方法也可以是 private 的),然后直接通过反射调用即可。当我们没看 SpringMVC 源码的时候,我们就知道接口方法最终肯定是通过反射调用的,现在,经过层层分析之后,终于在这里找到了反射调用代码。

最后再来说一下负责参数解析的 getMethodArgumentValues 方法:

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
  Object... providedArgs) throws Exception {
 MethodParameter[] parameters = getMethodParameters();
 if (ObjectUtils.isEmpty(parameters)) {
  return EMPTY_ARGS;
 }
 Object[] args = new Object[parameters.length];
 for (int i = 0; i < parameters.length; i++) {
  MethodParameter parameter = parameters[i];
  parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
  args[i] = findProvidedArgument(parameter, providedArgs);
  if (args[i] != null) {
   continue;
  }
  if (!this.resolvers.supportsParameter(parameter)) {
   throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
  }
  try {
   args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
  }
  catch (Exception ex) {
   // 省略...
  }
 }
 return args;
}
  • 首先调用 getMethodParameters 方法获取到方法的所有参数。
  • 创建 args 数组用来保存参数的值。
  • 接下来一堆初始化配置。
  • 如果 providedArgs 中提供了参数值,则直接赋值。
  • 查看是否有参数解析器支持当前参数类型,如果没有,直接抛出异常。
  • 调用参数解析器对参数进行解析,解析完成后,赋值。

是不是,很 easy!

4.ServletInvocableHandlerMethod

ServletInvocableHandlerMethod 则是在 InvocableHandlerMethod 的基础上,又增加了两个功能:

  • 对@ResponseStatus 注解的处理
  • 对返回值的处理

Servlet 容器下 Controller 在查找适配器时发起调用的最终就是 ServletInvocableHandlerMethod。

这里的处理核心方法是 invokeAndHandle,如下:

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
  Object... providedArgs) throws Exception {
 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
 setResponseStatus(webRequest);
 if (returnValue == null) {
  if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
   disableContentCachingIfNecessary(webRequest);
   mavContainer.setRequestHandled(true);
   return;
  }
 }
 else if (StringUtils.hasText(getResponseStatusReason())) {
  mavContainer.setRequestHandled(true);
  return;
 }
 mavContainer.setRequestHandled(false);
 try {
  this.returnValueHandlers.handleReturnValue(
    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
 }
 catch (Exception ex) {
  throw ex;
 }
}
  • 首先调用父类的 invokeForRequest 方法对请求进行执行,拿到请求结果。
  • 调用 setResponseStatus 方法处理@ResponseStatus​ 注解,具体的处理逻辑是这样:如果没有添加@ResponseStatus 注解,则什么都不做;如果添加了该注解,并且 reason 属性不为空,则直接输出错误,否则设置响应状态码。这里需要注意一点,如果响应状态码是 200,就不要设置 reason,否则会按照 error 处理。
  • 接下来就是对返回值的处理了.
    事实上,ServletInvocableHandlerMethod 还有一个子类 ConcurrentResultHandlerMethod,这个支持异步调用结果处理,因为使用场景较少,这里就不做介绍啦。
HTTP 代理服务器的设计与实现 HTTP 代理服务器的设计与实现 首先当然是最重要的代码:github地址 1) 实验目的 熟悉并掌握 Socket 网络编程的过程与技术;深入理解 HTTP 协议,掌握 HTTP 代理服 务器的基本工作原理;掌握 HTTP 代理服务器设计与编程实现的基本技能。 2) 实验内容 基于 java 实现了基本功能与全部附加功能,并增加了 https 的支持 (1) 设计并实现一个基本 HTTP 代理服... 阅读详情

相关推荐

从零构建:如何用MATLAB工具箱打造你的第一个多体动力学仿真模型

本文详细介绍了如何使用MATLAB的Simscape Multibody工具箱从零开始构建多体动力学仿真模型,特别适合初学者学习倒立摆系统的建模与仿真。文章涵盖环境准备、坐标系设置、物理模型构建、参数化建模及性能优化等关键步骤,帮助工程师快速掌握这一强大的仿真工具。

water的专栏 962

Springboot(二十一)@Aspect 切面注解使用

Spring AOP面向切面编程,可以用来配置事务、做日志、权限验证、在用户请求时做一些处理等等。用@Aspect做一个切面,就可以直接实现。 1.首先定义一个切面类,加上@Component @Aspect这两个注解 @Component @Aspect public class LogAspect { private static final Lo...

徐海兴的专栏 5万+

从零到一:TI AWR1843 Boost EVM与DCA1000 EVM的ADC数据采集实战指南

本文详细介绍了TI AWR1843 Boost EVM与DCA1000 EVM的ADC数据采集实战指南,涵盖硬件连接、软件配置、固件烧录、雷达参数设置及数据处理等关键步骤。通过MATLAB等工具,开发者可高效实现毫米波雷达数据采集,适用于自动驾驶、工业检测等领域。

weixin_29001327的博客 966

springboot切面不生效踩坑纪录

1.AOP无法切入private 切面无法切入到private方法,原因可以简单理解为就像反射不能获取私有成员一样,inner protected 一样失效 2.AOP无法切入方法内部调用 比方说service中有个方法A,controller中调用的是service.A(),而方法A()中内部调用了方法B和方法C。此时注解打在A()上面是没有问题的,打在B()或C()上是没有效果的,原因也是因为代理类的问题, 在 A() 的 中调用 this.B(), this对象并不是代理对象,而只是当前类的...

yiiy22的专栏 1657

Ubuntu安装opencv4.5(自己安装过程详细)

1.下载opencv 在opencv官网下载source版,下载链接 http://opencv.org/releases.html。别下载错版本 下载过程就不多说了。 2.安装过程 2.1解压 unzip opencv-4.5.0.zip cd opencv-4.5.0 2.2安装依赖的库 sudo apt-get install cmake sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-

weixin_45629790的博客 1万+

SAP与泛微OA集成(半导体行业)

本项目通过SAP PO中间件集成SAP与泛微OA在半导体行业的应用,由于行业特殊性,广泛深入应用了RSA加密等特性

集信通 1162

控制器判断void类型返回值

1.返回值类型为void类型 if(!returnType.getMethod().getReturnType().equals(Void.TYPE)){ //TODO } 2.返回值类型为ResponseEntity类型 Type type = returnType.getMethod().getGenericReturnType(); ...

OceanSky的专栏 2609

别再手动续期SSL证书了!用acme.sh配合阿里云DNS API,实现全自动HTTPS证书管理

本文详细介绍了如何使用acme.sh配合阿里云DNS API实现SSL/TLS证书的全自动管理,彻底解决手动续期带来的风险与不便。通过自动化部署流程,包括环境准备、API集成、多域名证书申请等关键步骤,帮助运维人员构建高效、可靠的HTTPS证书管理体系,显著提升安全性和运维效率。

weixin_29200485的博客 268

(一)还不会用springboot写接口?快看这里,手把手操作,一发入魂~

springboot入门项目,包括简单的接口开发(api),数据库操作(mybatis plus)和接口文档调试生成(knife4j)。

隐风的博客 1万+

卡门涡街可视化实战:从网格加密策略到动画后处理技巧

本文详细介绍了利用ANSYS Fluent进行卡门涡街可视化模拟的全流程,包括网格加密策略、求解器设置、涡街捕捉及动画后处理技巧。通过计算流体力学(CFD)方法,帮助工程师和研究人员高效模拟圆柱绕流现象,优化工程设计。

weixin_29309785的博客 414

YOLOv8与UNetV2融合:一种面向目标检测与图像分割的混合方法【附核心代码】

我们提出了一种基于YOLOv8和UNetV2相结合的混合架构。该架构利用YOLOv8作为主干进行目标检测,同时在YOLOv8的特征提取过程中,引入UNetV2来进行图像分割任务的增强。在该架构中,YOLOv8负责大范围目标检测和位置预测,而UNetV2则在检测网络的特征图基础上,通过其高效的上下文信息提取和细节恢复能力,进一步优化分割任务。在本文中,我们提出了一种改进YOLOv8的方法,通过引入图像分割网络UNetV2来提高图像分割检测性能。

一键难忘的博客 3524

Spring Boot 定义接口的方法是否可以声明为 private?

我们在 Controller 中定义接口的时候,一般都是像下面这样: @GetMapping("/01") public String hello(Map<String,Object> map) { map.put("name", "javaboy"); return "forward:/index"; } 估计很少有人会把接口方法定义成 private 的吧?那我们不禁要问,如果非要定义成 private 的方法,那能运行起来吗? 带着这个疑问,我们开始今天的源码解读~ 在我

江南一点雨的专栏 1万+

高质量文献综述原来这么写!借助Gemini 3 Pro+四步法,手把手教你写出有逻辑深度的综述

总结与展望先总结现状,说明前人已经做到什么地步了,再指出缺口,前人没解决什么问题、方法有什么局限等等,最后再在这个缺口的基础上,提出你的未来研究方向。当你有个复杂的研究题目,但没办法拆解出关键词,就可以让Gemini 3 Pro来辅助帮你拆解,并帮你写专业的检索式,若是找英文文献,还能帮你将中文关键词翻译成地道的专业术语。做文献笔记,可以建立文献笔记矩阵,可以用Excel建个表格,横向是文献,纵向是关键要素,包括作者/年份、研究问题/假设、理论框架/模型、研究方法/数据来源、核心结论、局限性/Gap。

智能AI让学术科研更容易 989

Spring Boot 定义接口的方法是否可以声明为 private?(1)

接下来我们来简单看下 HandlerMethod。这个方法主要是确认了一下 handler 的类型,如果 handler 是 String 类型,则根据 beanName 从 Spring 容器中重新查找到 handler 对象,然后构建 HandlerMethod:这里的参数都比较简单,没啥好说的,唯一值得介绍的地方有两个:parameters 和 responseStatus。parameters。

2401_83915900的博客 832

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

解救应用启动危机:Spring Boot的FailureAnalyzer机制

探讨Spring Boot中的FailureAnalyzer机制,帮助解决应用启动失败的难题。对FailureAnalyzer的工作原理、生效方式以及自定义的基本步骤进行介绍,包括注册方式说明和实例演示。希望可以帮助更好地理解并利用FailureAnalyzer来诊断和解决应用启动失败的问题。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 9万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: 分析Java中 CharSequence源码
下一篇: 牛!阿里技术官纯手打《385页图解Tomcat整体架构笔记》
Java_ttcd
博客等级 码龄4年 198粉丝 190原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值