咱们在 Controller 中界说接口的时分,一般都是像下面这样:

@GetMapping("/01")
public String hello(Map<String,Object> ma电脑开机黑屏p) {
map.put("name", "javaboy");
return "forward:/index";
}

估量很少有人会把接口办法界说成 private 的吧?那咱们不由要问,假定非要界说成 private 的办法,Java那能作业起来http://www.baidu.com吗?

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

在咱们运用 Spring Boot 的时分,常常会看到 HandlerMethod 这个类型,例如咱们在界说阻遏器的时分,假定阻遏政策是一个办法,则 preHandle 的第三个参数便是 Handler电脑Method(以下案例选数组初始化自松哥之前的视频:手把手教你 Spring Boot 自界说注解):

@Component
public class IdempjavascriptotentInterceptor implements HandlerIn数组terceptor {
@Autowired
TokenService tokenService;
@Override
public bhttps和http的差异oolean preHandle(HttpServspringboot和springmvc的差异letRequest request数组词, HttpServletResponse response, Object handler) throws Exception {
if数组去重的5种办法 (!(handler instanceof HandlerMethod)) {
return true;
}
//省掉...
return true;
}
//...
}

咱们在阅览 SpringMVC 源码的时分,也会重复看到这个 Hand数组词lerMethod,那么它到底是什么意思?今日我想和小伙伴们捋一捋这个问题,把这个问题搞清楚了,前面的问题咱们也就懂了。

1.概电脑快捷键

Spring Boot 界说接口的办法是否能够声明为 private?

能够看到,HandlerMethod 体系Java下的类并不多:

HandlerMethod

封装 Handlhttp 404er 和具体处理央求的 Method。

InvocableHandlerMethod

在 HandlerMethod 的根底上添加了调用的功用。

ServletInvocableHandlerMet数组的界说hod

在 InvocableHandlerMethod 的根底上增了对 @ResponseStathttpwatchus 注解的支撑、添加了对返回值的处理。

ConcurrentResultHandlerMethod

在 ServletInvocableHandlerMethod 的根底上,添加了对异步作用的处数组c言语理。springboot面试题

基本上便是这四个,接下来松哥就来具体说一说这四个组件。

2.HandlerMethod

2.1 bridgedMethod

在正式开始介绍 HandlerMethod 之前,想先和咱们聊聊 bridgedMethod,因为在 HandlerMethod 中将会涉及到这个东西,而有的小伙伴或许还没听说过 bridgedMethod,因此松哥在这儿做一个简略介绍。

首要考考咱们,下面这段java面试题代码编译会报错吗?

public interface Animal<T> {
void eat(T数组 t);
}
public class Cat implements Animal<Strinjava游戏g> {
@Override
public void eat(String s)电脑开机黑屏 {
System.out.println("cathttp 500 eat " + s);
}
}
public class Demo01 {
public static void main(StrJavaing[] arJavags) {
Animal animal = new Cat();
animal.eat(new Ojava环境变量装备bject());
}
}

首要咱们界说了一个 Animal 接口,里面界说了一个 eat电脑怎样截图 办法,一起声明https和http的差异晰一个泛型。Cat 完成了 Animal 接口,将泛型也界说为了 String。当我调用的时分,声明类型是 Animal,实践类型是 Cat,这个时分调 eat 办法传入了 Object 目标咱们猜猜http://192.168.1.1登录会怎样样?假定调用 eat 办法电脑开机黑屏时传入的是 Stjava环境变量装备ring 类型那就必定没问题,但假定不是 String 呢?

松哥先说结论:编译没问题,作业报错。

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

Spring Boot 界说接口的办法是否能够声明为 private?

咱们看到,在我写代码的时分,开发工具会给我提示,这个参数类型是 Object,有的小伙伴会觉得乖僻,分明是泛型,怎样变成 Objec数组的界说t 了?

咱们可springboot和springmvc的差异以经过反射检查 Cat 类中到底有哪些办法电脑锁屏快捷键,代码如下:

public class Demo01 {
public static void main(String[] args) {
Methhttp 404od[] methods = Cat.class.getMethod电脑截图快捷键s();
for (Method methohttp 404d : methospringboot面试题ds) {
String name = method.getNam数组去重e();
Class<?>[] parameterTypes = method.gespringboot面试题tPara电脑开不了机meterTypes();
System.out.println(name+"("+ Arrays.toString(parameterTypes) +")");
}
}
}

作业作用如下:

Spring Boot 界说接口的办法是否能够声明为 private?

能够看到,在实践作业进程中,竟然有两个 eat 方电脑截图快捷键法,一个的参数为数组和链表的差异 String 类型,另一个参数为 Object数组和链表的差异 类型,这是怎样回事呢?

springboot主动安装个参数类型为 Object 的办法其实是 Java 虚javahdxx拟机在作业时创建出来的,这个办法便是咱们所说的 bridge method。本节的小标题叫做 bridgedMethod,这是 HandlerMethod 源码中的变量名,bridge 结束多了一个 d,意义变成了被 bridge 的办法http://www.baidu.com,也便是参数为 String 的原办法,咱们在接下来的源码中看到了 bridgedMethod 就知道这表明参数类型不变的原办法。

2.2 HandlerMethod 介绍

接下来咱们来简略看下 Handlespringboot发动进程rMethod。

在咱们前面剖析 Handlejava模拟器rM数组去重的5种办法ap数组公式ping 的时分(参见:SpringMVC 九大组件之 HandlerMapping 深入剖析),里面有涉及到 HandlerMethod,创建 HandlerMethod 的进口办法是 createWspringboot常用注解ithReso电脑键盘功用根底知识lvedBean,因此这儿咱们就从该办法开始看起:

public HandlerMethod createWithR电脑截图快捷键esolvedBean() {
Object handler = this.HTTPbean;
if (this.bean instanceof String) {
Strispringboot发动进程ng beanName = (String) this.bejavascriptan;
handler = this.beanFactory.getBean(beanName);
}
return new HandlerMethod(this, handler);
}

这个办法首要是确认了一下 handler 的类型,假定 handler 是 String 类型,则根据 beanName 从 Sprin电脑截图快捷键g 容器中从头查找到 ha电脑蓝屏ndle电脑开机黑屏r 目标,然后构建http协议 HandlerMethod:

private HandlerM数组ethod(HandlerMethod handlerMethod, Ojava环境变量装备bject handler) {
this.bean = handhttp://192.168.1.1登录ler;
thJavais.beanFactory = handlerMethod.beanFactory;
this.beanType = handlerMethod.bjava编译器eanType;
this.method = handlerspringboot项目建立Method.method;
this.brjavaeeidgedMjavascriptethohttps和http的差异d = handlerMet电脑hod.bridgedMethod;
this.parameters = h电脑蓝屏andlerMethodjavascript.pspringboot发动进程arameters;
this.responseStatus = handlerMethod.rjava游戏esponseStatuspringboot主动安装s;
this.responseStahttpwatchtusReason = hjavaeeandlerMethod.responseStatusReason;
this.resolvedFromHandlerMethod = handlerMethojava游戏d;
this.description = handlerMethod.description;
}

这儿的参数都比较简略,没啥好说的,仅有值得介绍的当地有两个:parameters 和 responseStaspringboot常用注解tus。

parameters

parameters 实践http协议上便是办法参数,对应的类型是 MethodParameter,这个类的源码我这儿就不贴出来了,首Java要和我springboot主动装备的原理们说一下封装的内容包含:参数的java模拟器序号(parameterInjava根底知识点dex),参数嵌套级别(nestingLevel),参数类型(parameterType),参数的注解(parameterAnnotations),参数称谓springboot面试题2021查找器(parameterNameDiscoverer),参数称谓(parjava怎样读ameterName)等。

HandlerMethod 中还供给了两个内部类来封装 MethodParameter,分别是http 302

  • HandlerMethodParameter:这个封装办法调电脑截图快捷键ctrl加什么用的参数。
  • ReturnValueMethodParameter:这个继数组指针承自 Han数组c言语dlerMethodParameter,它封装了办法的返回值,返回值里面的https和http的差异 pa数组的界说rameterIndex 是 -1http 500电脑开不了机

留神,这两者中的 method 都是 bridspringboot面试题gedMethod。

responseS电脑怎样康复出厂设置tatus

这个首要是处理办法的 @ResponseStatus 注解,这个注解用来描绘办法的照顾状况码,运用办法像下面这样:

@GetMapping("/04")httpclient
@ResponseBody
@ResponseStatus(code = HttpStatus.OK)
public void hello4(@SessionAttribute("name电脑锁屏快捷键") String name) {
System.out.println("name = " + name);
}

从这段代码中咱们能够看到,其实 @数组去重ResponseStatus 注解灵活性很差,不实用,当咱们界说一个接口的时分,很难预知到该接口的照顾状况码是 200。

在 handler电脑开不了机Method 中,在调用其结构办法的时分,都会调用 evaluateResponseStatus 办法处理 @ResponseSjava模拟器tatushttp://192.168.1.1登录解,如下:

private void evaluateResponseStatus() {
ResponseStatus annotahttp署理tion = getMethodAnnotation(ResponseStatus.class)springboot项目建立;
if (anno电脑tation ==数组指针 null) {
annotation = AnnotatedElementUtils.springboot项目建立findMergedAnnotatspringboot是什么结构ion(getBeanType(javascript), ResponseStatus.class);
}
if (annotation != nulHTTPl) {
this.responseSt数组去重的5种办法atus = annotation.code();
this.respjava根底知识点onseStatusReason = annotation.reason();
}
}

能够看到,这段代码也比较简略,找到http 500注解,把里面的值解析出来,赋值给相应的变量。

这下小伙伴们应该理解了 HandlerMethod 大概是个怎样回事。

3.InvocableHandlerMethod

看姓名就知道,InvocableHandlerMethod 可Spring+Boot以调用 HandlerMethod 中springboot主动安装的具体办法,也便是 brspringboot面试题idgedMethod。咱们先来看下 InvocableHandlerMethod 中声明的特征:

private HandlerMethodArgumentR电脑蓝屏esolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
privathttp协议e ParameterNamhttpclienteDiscovHTTPerer parameterNameDiscoverer = new Djava根底知识点efaultParameterNameDiscov数组初始化erer();
@Nullable
private WebDataBinderFactory dataBinderFactory;

首要便是这三个特征:

  • resolvers:这个不用说,参数解析器,前面的文章中松哥现已和咱们聊过这个问题了。
  • parameterNameDiscoverer:这个用来获取参数称谓,在 Mspringboot发动进程ethodParameter 中会用到。
  • dataBinderFactjava面试题ory:这个用来创建 WebDataBinder,在参数解析器中会用到。

具体的央求调用办法是 invokeForRequest,咱们一起来看下:

@Nullable
public Object invok数组和链表的差异eForRequest(NativeWebRequest request, @Nullabl电脑蓝屏e ModelAnd数组排序ViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[电脑锁屏快捷键] args = getMethodArgume电脑开不了机ntValues(request, mavContainer, providedArgs数组去重);
retu电脑怎样康复出厂设置rn doInvoke(args);
}
@Nullable
protected Object doInvoke(Object... args) throws Exception {
Method method = getBridgedMe电脑键盘功用根底知识thod();
Refle电脑蓝屏ctionUtils.makeAccessible(m电脑怎样康复出厂设置ethod);
trHTTPy {
if (KotlinDetector.isSuspendinjavahdxxgFunctiojava游戏n(method数组去重)) {
return CoroutinesUtils.invokeSuspendingFuncjavascripttion(method, getBean(), args);
}
return meth电脑开机黑屏od.invoke(getBean(), args);
}
catch (InvocationTar数组去重的5种办法getExceptio数组排序n ex) {
// 省掉 ...
}
}

首要调用 getMethodArgumentValues 办法按次第获取到全部参数的值,这些参数数组的界说值组成一个数组,然后调用 doInvoke 办法执行,在 doInspringboot面试题vok数组去重e 办法中,首要获取到 bridgedMethod,并设置其可见(意味着咱们在 Controller 中界说的http署理接口办法也能够是 private 的),然后直接经过反射调用springboot菜鸟教程即可。当咱们没看 Shttp 302pringMVC 源码的时分,我数组c言语们就知道接口方电脑法毕竟必定是经过反射调用的,现在,经过层层剖析之后,总算在这儿找到了反射调用代码。

终究松哥再来说一下负责参数解java模拟器析的 getMethodArgumentVa电脑怎样截图lues 办法:

protected Object[] getMethodArgumentValuspringboot主动装备的原理es(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodPa电脑截图快捷键rameter[] parameters = getMethodParameters();
if (ObjectUtils.isEhttp://192.168.1.1登录mpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[电脑锁屏快捷键parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter =springboot主动安装 parameters[i];
parameter.initP数组c言语arameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidejava根底知识点dArgument(parameter, providedArgs);
if (arjava编译器gs[i] != null) {
contspringboot主动安装inue;
}
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(phttpwatcharameter, "No suitable resolver"));
}
try {
args[i] =java编译器 this.resolvers.resolveArgument(数组初始化parameter, mavContainer, request, this.dataBinderFactory);
}
catchhttp 302 (Exception ex) {
// 省掉...
}
}
return args;
}
  1. 首要调用 getMethodParameters 办法获取到办法的全部参数。
  2. 创建 args 数组用来保存参数的值。
  3. 接下来一堆初始化装备。
  4. 假定 providedArgs 中供给了参数值,则直接赋值。
  5. 检查是否有电脑锁屏快捷键参数解析器支撑其时参数类型,假定没有,直接抛出反常。
  6. 调用参数解析器对参数进行解析,解析完成后数组排序,赋值。

是不是,很 eas数组c言语y!

4.ServletInvocableHa电脑开不了机ndlerMethod

ServletInvocableHandlerMethod 则是在 Invoc电脑开机黑屏ableHandlerMethod 的根底上,又添加了springboot面试题两个功用:

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

Servlet 容器下 Controller 在查找适配器时建议调用的毕竟httpwatch便是 ServletInvocableHandlerMethod。

这儿的处理核心方电脑蓝屏法是 invokeAndHandle,如下:

public void ispringboot主动装备的原理nvokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object returnValue = invokeForReqspringboot是什么结构uest(webRequest, mavContspringboot面试题ainer, providedA数组去重的5种办法rgs);
setResponseStatus(w电脑ebRequest);
ifspringboot常用注解 (returspringboot和springmvc的差异nValue == null) {
if (isRequestNotModified(webRequest) || getRespringboot项目建立sponseStatus() != null数组指针 || mavContainer.isRequestHandl数组排序ed()) {
disableContentCachingIf电脑蓝屏Necessary(webRequest);
mavContainer.set数组排序RequestHandlhttp://192.168.1.1登录ed(true);
return;
}
}
else if (StringU数组指针tils.hasText(getResponseStatusReasjava面试题on())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainespringboot发动进程r.setRequestHandled(false);
try {
this.returnValueHa数组去重ndlers.handleReturnValue(
returnjava怎样读Value, getReturnValueType(re数组的界说turnValue), mavContainer, webReqhttp 404uest);
}
catch (Exception ex) {
throw ex;
}
}
  1. 首要调用父类的 invokeForRequest 办法对央求进行执行,拿到央求作用。
  2. 调用 setResponseStatus 办法处理 @ResponseStatus 注解,详数组的界说细的处理逻辑是这样:假定没有添加 @ResponseStatus 注解,则什么都不做;假定添加了该注解,并且 reason 特征不为空,则直接输出差错,否则设电脑开不了机置照顾java模拟器状况码。这儿需求留神一点,假定照顾状况码是 200,就不要设置 reason,否则会按照 error 处理。
  3. 接下来便是对返回值的处理了,returnValueHandlers#handleReturnValue 办法松哥在之前的文章中和咱们专门介绍过,这儿就不再赘述,传送门:Spring Boot 中怎样共同 API 接口照顾格式?。

事实上,ServletInv数组词ocableHandlerMjava怎样读ethod 还有一个子类 ConcurrehttpclientntResultHandlerMethod,这个支撑异步调用作用处理,因为运用场景较少,这儿就不做介绍啦。

5.小结

现在java环境变量装备咱们能够答复数组公式文章标题提出的问题了吧?