SpringMVC常见组件之HandlerMethodArgumentResolver解析-1

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: SpringMVC常见组件之HandlerMethodArgumentResolver解析-1

在前面我们分析SpringMVC常见组件之HandlerAdapter分析中提到过如下过程

RequestMappingHandlerAdapter.invokeAndHandle(webRequest, mavContainer);
--ServletInvocableHandlerMethod.invokeAndHandle(webRequest, mavContainer);
---`Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);`
---Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

其中最重要的一步就是在InvocableHandlerMethod中解析请求传输参数,方法源码如下所示:

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) {
      // Leave stack trace for later, exception may actually be resolved and handled...
      if (logger.isDebugEnabled()) {
        String exMsg = ex.getMessage();
        if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
          logger.debug(formatArgumentError(parameter, exMsg));
        }
      }
      throw ex;
    }
  }
  return args;
}

这里可以看到args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);其是通过查找相应的参数解析器来获取请求中传输数据。这是整个流程中核心的一步,也是在反射调用目标方法前必要的一步。

【1】HandlerMethodArgumentResolver

源码如下所示,其是一个策略接口主要用来将请求中的参数值解析到目标方法参数中。提供了两个方法让子类实现:supportsParameter用来判断当前参数解析器是否能够处理参数,resolveArgument方法处理参数然后返回结果。

public interface HandlerMethodArgumentResolver {
   // 当前参数解析器是否支持当前参数对象
  boolean supportsParameter(MethodParameter parameter);
   // 返回一个解析好的参数值(对象),可能为null
   // mavContainer提供了获取request中model的方式;
   // 当需要进行数据绑定和类型转换的时候,WebDataBinderFactory提供了创建WebDataBinder方式
  @Nullable
  Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}


我们再来看一下其家族树图示

如下所示,有34个类,值得一提的是某些参数解析器还实现了返回结果处理器的接口,如


ModelMethodProcessor。
MapMethodProcessor
ErrorsMethodArgumentResolver
PathVariableMapMethodArgumentResolver
AbstractNamedValueMethodArgumentResolver
RequestHeaderMethodArgumentResolver
RequestAttributeMethodArgumentResolver
RequestParamMethodArgumentResolver
AbstractCookieValueMethodArgumentResolver
ServletCookieValueMethodArgumentResolver
ExpressionValueMethodArgumentResolver
SessionAttributeMethodArgumentResolver
MatrixVariableMethodArgumentResolver
PathVariableMethodArgumentResolver
RequestHeaderMapMethodArgumentResolver
ModelMethodProcessor
ModelAttributeMethodProcessor
ServletModelAttributeMethodProcessor
ServletResponseMethodArgumentResolver
SessionStatusMethodArgumentResolver
RequestParamMapMethodArgumentResolver
PrincipalMethodArgumentResolver
ContinuationHandlerMethodArgumentResolver
AbstractMessageConverterMethodArgumentResolver
RequestPartMethodArgumentResolver
AbstractMessageConverterMethodProcessor
RequestResponseBodyMethodProcessor
HttpEntityMethodProcessor
AbstractWebArgumentResolverAdapter
ServletWebArgumentResolverAdapter
UriComponentsBuilderMethodArgumentResolver
HandlerMethodArgumentResolverComposite
ServletRequestMethodArgumentResolver
RedirectAttributesMethodArgumentResolver
MatrixVariableMapMethodArgumentResolver

解析器与参数类型表格

如下表格中“是否解析返回结果”,也就是说其同时实现了HandlerMethodReturnValueHandler接口,可以处理返回结果。



3.png

4.png

5.png


@PathVariable Map表示标注了@PathVariable 注解且参数是Map类型并且没有为参数指定名称如在这里@PathVariable("map") Map map。@PathVariable !Map表示参数使用了@PathVariable 注解但是参数类型不是Map。


如上表格所示,这里XXXXProcessor 表示实现了参数解析器和返回结果处理器。而XXXXResolver是单纯的参数解析器。


接下来我们着重分析几个常见的参数解析器。

【2】HandlerMethodArgumentResolverComposite

通过将处理动作委派给内部注册的一系列HandlerMethodArgumentResolvers来实现功能。其内部有两个常量如下:

private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
    new ConcurrentHashMap<>(256);


其首先应用了组合模式,无论InvocableHandlerMethod调用HandlerMethodArgumentResolverComposite还是单个具体的HandlerMethodArgumentResolver,其行为都是一致的。


什么行为?第一是判断是否支持当前参数类型也就是supportsParameter方法;第二就是解析参数的方法resolveArgument。


其次应用了委派/策略模式,InvocableHandlerMethod在解析参数的时候根本不知道也不关心具体的HandlerMethodArgumentResolver是谁,只要将动作扔给HandlerMethodArgumentResolverComposite就可以拿到参数值(结果)。

① supportsParameter


如下所示,HandlerMethodArgumentResolverComposite将判断是否支持参数的动作交给了具体的HandlerMethodArgumentResolver 。其首先从argumentResolverCache根据parameter获取一个HandlerMethodArgumentResolver ,如果不为null直接返回。如果为null则从argumentResolvers获取一个支持当前parameter的HandlerMethodArgumentResolver 放入argumentResolverCache然后返回。

@Override
public boolean supportsParameter(MethodParameter parameter) {
  return getArgumentResolver(parameter) != null;
}
@Nullable
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;
}

② resolveArgument

如下所示,HandlerMethodArgumentResolverComposite将解析参数的动作交给了具体的HandlerMethodArgumentResolver 。调用getArgumentResolver方法获取一个HandlerMethodArgumentResolver 然后进行解析,如果获取不到HandlerMethodArgumentResolver 则抛出异常IllegalArgumentException。

@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
    NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
  HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
  if (resolver == null) {
    throw new IllegalArgumentException("Unsupported parameter type [" +
        parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
  }
  return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

【3】AbstractNamedValueMethodArgumentResolver

① 概述

一个抽象基类,用于从命名值解析方法参数。请求参数、请求头和路径变量是命名值的示例。每个都可能有一个名称、一个必需的标志和一个默认值。子类定义如何处理以下信息:


获取方法参数的命名值信息

将名称解析为参数值

当参数值必须的时候,处理参数值为空的情况

可选地处理已解析的值

将创建一个WebDataBinder,以便在解析的参数值与方法参数类型不匹配时对其应用类型转换。

什么是“命名值信息”?其实是NamedValueInfo,源码如下所以包含name、required以及defaultValue三个属性。

protected static class NamedValueInfo {
  private final String name;
  private final boolean required;
  @Nullable
  private final String defaultValue;
  public NamedValueInfo(String name, boolean required, @Nullable String defaultValue) {
    this.name = name;
    this.required = required;
    this.defaultValue = defaultValue;
  }
}

其子类图示如下所示,主要用来处理请求头、请求属性、会话属性、Spring表达式( @Value)、URL路径变量、CookieValue及其他。这里面最重要也最常见的就是RequestParamMethodArgumentResolver。


023658f1038e439da55da1b24ea2b7d0.png

其提供了如下抽象方法让子类实现:

// 获取参数的NamedValueInfo 对象
protected abstract NamedValueInfo createNamedValueInfo(MethodParameter parameter);
// 解析参数名称
@Nullable
protected abstract Object resolveName(String name, MethodParameter parameter, NativeWebRequest request)
    throws Exception;

方法的默认实现

handleMissingValue默认抛出ServletRequestBindingException异常,可以让子类重写。

protected void handleMissingValue(String name, MethodParameter parameter) throws ServletException {
  throw new ServletRequestBindingException("Missing argument '" + name +
      "' for method parameter of type " + parameter.getNestedParameterType().getSimpleName());
}

handleNullValue方法默认实现,如果参数类型Boolean则返回false,否则如果参数类型是paramType.isPrimitive抛出IllegalStateException异常。

@Nullable
private Object handleNullValue(String name, @Nullable Object value, Class<?> paramType) {
  if (value == null) {
    if (Boolean.TYPE.equals(paramType)) {
      return Boolean.FALSE;
    }
    else if (paramType.isPrimitive()) {
      throw new IllegalStateException("Optional " + paramType.getSimpleName() + " parameter '" + name +
          "' is present but cannot be translated into a null value due to being declared as a " +
          "primitive type. Consider declaring it as object wrapper for the corresponding primitive type.");
    }
  }
  return value;
}

handleResolvedValue则默认是个空方法。

protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter,
    @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
}

需要注意的是在createNamedValueInfo后还调用了updateNamedValueInfo,我们看其默认实现:

private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) {
  String name = info.name;
  // 如果name为空,则将参数的名字赋予name
  if (info.name.isEmpty()) {
    name = parameter.getParameterName();
    if (name == null) {
      throw new IllegalArgumentException(
          "Name for argument of type [" + parameter.getNestedParameterType().getName() +
          "] not specified, and parameter name information not found in class file either.");
    }
  }
  // 如果默认值为ValueConstants.DEFAULT_NONE,则赋予null
  String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue);
  return new NamedValueInfo(name, info.required, defaultValue);
}

OK,接下来我们看一下入口核心方法resolveArgument。

③ 模板方法resolveArgument

其是一个典型的模板方法模式,方法类型使用了final避免被子类覆盖。定义好算法的过程,其中某些步骤为抽象方法让子类实现。

@Override
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
    NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
  NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
  MethodParameter nestedParameter = parameter.nestedIfOptional();
  Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
  if (resolvedName == null) {
    throw new IllegalArgumentException(
        "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
  }
  Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
  if (arg == null) {
    if (namedValueInfo.defaultValue != null) {
      arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
    }
    else if (namedValueInfo.required && !nestedParameter.isOptional()) {
      handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
    }
    arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
  }
  else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
    arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
  }
  if (binderFactory != null) {
    WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
    try {
      arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
    }
    catch (ConversionNotSupportedException ex) {
      throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
          namedValueInfo.name, parameter, ex.getCause());
    }
    catch (TypeMismatchException ex) {
      throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
          namedValueInfo.name, parameter, ex.getCause());
    }
    // Check for null value after conversion of incoming argument value
    if (arg == null && namedValueInfo.defaultValue == null &&
        namedValueInfo.required && !nestedParameter.isOptional()) {
      handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
    }
  }
  handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
  return arg;
}

方法源码解释如下:

① 获取NamedValueInfo 信息包括参数name,是否必须,默认值;

② 尝试解析嵌套的参数得到具体的MethodParameter ;

③ 解析参数的name,这里会判断是否为SpEL表达式如@Value("${com.jane.name}" )String name,那么返回@Value;

④ 根据参数的name解析参数值;

⑤ 如果参数值为null,则尝试根据默认值、是否必须等获取,最终调用handleNullValue方法;

⑥ 如果参数值为""且默认值不为null,则再次尝试调用resolveEmbeddedValuesAndExpressions(用来处理SpEL表达式);

⑦ 如果binderFactory不为null,则创建WebDataBinder–这个过程会进行数据绑定器的初始化;

⑧ 如果类型不匹配则尝试进行类型转换;

⑨ 抛出MethodArgumentConversionNotSupportedException或者TypeMismatchException;

⑩ handleMissingValue处理缺值单required==true&&defaultValue==null的情况

(11) handleResolvedValue处理解析得到的value,该方法在PathVariableMethodArgumentResolver中有实现。

如果方法参数为String testSpEL(@Value("${com.jane.name}" )String name),那么namedValueInfo如下所示

99e768ac5e5747e08bdf7f7cb46526fe.png

如果方法参数为String testSimple(Integer age),那么namedValueInfo如下所示


90b84ce8b3164ababd23701b6b6fcc5b.png

如果方法参数为String testPath(@PathVariable Integer id),那么namedValueInfo如下所示

【4】RequestParamMethodArgumentResolver


解析 @RequestParam("指定名字") Map 或者@RequestParam !Map或者MultipartFile 类型(使用MultipartResolver)Part类型(使用Servlet3.0 api)或者BeanUtils.isSimpleProperty也就是简单类型的参数。如果参数类型是@RequestParam Map那么将会使用RequestParamMapMethodArgumentResolver来处理。


如果目标参数类型不匹配,那么将会使用WebDataBinder尝试进行类型转换。

① supportsParameter

public boolean supportsParameter(MethodParameter parameter) {
  if (parameter.hasParameterAnnotation(RequestParam.class)) {
    if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
      RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
      return (requestParam != null && StringUtils.hasText(requestParam.name()));
    }
    else {
      return true;
    }
  }
  else {
    if (parameter.hasParameterAnnotation(RequestPart.class)) {
      return false;
    }
    parameter = parameter.nestedIfOptional();
    if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
      return true;
    }
    else if (this.useDefaultResolution) {
      return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
    }
    else {
      return false;
    }
  }
}


方法源码表示其主要支持如下类型参数:

  • @RequestParam("指定名字") Map map;
  • @RequestParam !Map,也就是标注了@RequestParam注解非Map类型参数 ;
  • MultipartFile类型或者Part类型或者对应集合|数组类型;
  • 简单类型

这里我们看一下什么是简单类型。

public static boolean isSimpleProperty(Class<?> type) {
  Assert.notNull(type, "'type' must not be null");
  return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
}
public static boolean isSimpleValueType(Class<?> type) {
  return (Void.class != type && void.class != type &&
      (ClassUtils.isPrimitiveOrWrapper(type) ||
      Enum.class.isAssignableFrom(type) ||
      CharSequence.class.isAssignableFrom(type) ||
      Number.class.isAssignableFrom(type) ||
      Date.class.isAssignableFrom(type) ||
      Temporal.class.isAssignableFrom(type) ||
      URI.class == type ||
      URL.class == type ||
      Locale.class == type ||
      Class.class == type));
}     


也就是说参数类型是简单类型或者简单类型的数组。这里首先限定了非Void,然后下面任何一种类型都属于简单类型:


Primitive Type或者其包装类型如java.lang.Boolean、java.lang.Character、java.lang.Byte、java.lang.Short、java.lang.Integer、java.lang.Long、java.lang.Float、java.lang.Double。注意java.lang.Void不被认为是简单类型。

java.lang.Enum

java.lang.CharSequence

java.lang.Number

java.util.Date

java.time.temporal.Temporal

java.net.URI

java.net.URL

java.util.Locale

java.lang.Class

② RequestParamNamedValueInfo


RequestParamMethodArgumentResolver.RequestParamNamedValueInfo,其是RequestParamMethodArgumentResolver的静态内部类继承自NamedValueInfo 。

private static class RequestParamNamedValueInfo extends NamedValueInfo {
  // name="",required=false,defaultValue=ValueConstants.DEFAULT_NONE
  public RequestParamNamedValueInfo() {
    super("", false, ValueConstants.DEFAULT_NONE);
  }
  //name=annotation.name(),required=annotation.required(),defaultValue=annotation.defaultValue()
  public RequestParamNamedValueInfo(RequestParam annotation) {
    super(annotation.name(), annotation.required(), annotation.defaultValue());
  }
}

可以看到该类提供了两个构造函数直接调用了super构造函数,分别定义两种(是否有RequestParam注解)NamedValueInfo 实例。

③ resolveArgument

RequestParamMethodArgumentResolver自身没有resolveArgument,其提供了createNamedValueInfo、resolveName、handleMissingValue以及contributeMethodArgument方法供父类AbstractNamedValueMethodArgumentResolver使用。

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

方法解释如下:


① 尝试获取HttpServletRequest请求,如果不为null则继续判断请求是否为MultipartHttpServletRequest请求或者内容类型是否以multipart/开头,如果是,则继续尝试进行Multipart或者Part解析返回对应的单个对象或者集合类型或者数组类型;如果解析结果mpArg != MultipartResolutionDelegate.UNRESOLVABLE则直接返回。通俗点将,这里会尝试进行文件上传解析返回MultipartFile对象或者MultipartFile[]

② 尝试获取MultipartRequest请求,如果不为null,则尝试解析获取List files然后赋予arg;

③ 如果arg为null,则尝试进行最基本的参数解析-- String[] paramValues=request.getParameterValues(name);

④ 返回arg。

④ handleMissingValue处理缺值情况

@Override
protected void handleMissingValue(String name, MethodParameter parameter, NativeWebRequest request)
    throws Exception {
  HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
  if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
    if (servletRequest == null || !MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
      throw new MultipartException("Current request is not a multipart request");
    }
    else {
      throw new MissingServletRequestPartException(name);
    }
  }
  else {
    throw new MissingServletRequestParameterException(name,
        parameter.getNestedParameterType().getSimpleName());
  }
}

根据参数不同类型,分别抛出MultipartException、MissingServletRequestPartException或者MissingServletRequestParameterException异常。其中这里有我们常见的Current request is not a multipart request。

SpringMVC常见组件之HandlerMethodArgumentResolver解析-2https://developer.aliyun.com/article/1382042

目录
相关文章
|
3月前
|
前端开发 JavaScript
React 步骤条组件 Stepper 深入解析与常见问题
步骤条组件是构建多步骤表单或流程时的有力工具,帮助用户了解进度并导航。本文介绍了在React中实现简单步骤条的方法,包括基本结构、状态管理、样式处理及常见问题解决策略,如状态管理库的使用、自定义Hook的提取和CSS Modules的应用,以确保组件的健壮性和可维护性。
92 17
|
11天前
|
索引
【Flutter 开发必备】AzListView 组件全解析,打造丝滑索引列表!
在 Flutter 开发中,AzListView 是实现字母索引分类列表的理想选择。它支持 A-Z 快速跳转、悬浮分组标题、自定义 UI 和高效性能,适用于通讯录、城市选择等场景。本文将详细解析 AzListView 的核心参数和实战示例,助你轻松实现流畅的索引列表。
32 7
|
2月前
|
XML Java 开发者
Spring底层架构核心概念解析
理解 Spring 框架的核心概念对于开发和维护 Spring 应用程序至关重要。IOC 和 AOP 是其两个关键特性,通过依赖注入和面向切面编程实现了高效的模块化和松耦合设计。Spring 容器管理着 Beans 的生命周期和配置,而核心模块为各种应用场景提供了丰富的功能支持。通过全面掌握这些核心概念,开发者可以更加高效地利用 Spring 框架开发企业级应用。
89 18
|
1月前
|
传感器 监控 安全
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
|
3月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
3月前
|
前端开发 UED
React 文本区域组件 Textarea:深入解析与优化
本文介绍了 React 中 Textarea 组件的基础用法、常见问题及优化方法,包括状态绑定、初始值设置、样式自定义、性能优化和跨浏览器兼容性处理,并提供了代码案例。
131 8
|
4月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
299 2
|
4月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
99 2
|
4月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
144 2
|
9天前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。

热门文章

最新文章

推荐镜像

更多