2024年C C++最新SpringMVC这篇文章吃透了,最少最少涨5000,2024年阿里+头条+腾讯大厂C C++笔试真题

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

@ComponentScan(“com.javacode2018.springmvc.chat12”)
@EnableWebMvc //1:使用EnableWebMvc开启springmvc注解方式配置
public class MvcConfig implements WebMvcConfigurer {

/**
     * 2、添加视图解析器(可以添加多个)
     *
     * @param registry
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix(“/WEB-INF/view/”);
        resolver.setSuffix(“.jsp”);
        resolver.setOrder(Ordered.LOWEST_PRECEDENCE);
        registry.viewResolver(resolver);
    }

@Autowired
    private MyInterceptor myInterceptor;

/**
     * 3、添加拦截器(可以添加多个)
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this.myInterceptor).addPathPatterns(“/**”);
    }

/**
     * 4、配置静态资源访问处理器
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(“/static/**”).addResourceLocations(“/static/”);
    }

/**
     * 5、配置文件上传解析器
     *
     * @return
     */
    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
        //maxUploadSizePerFile:单个文件大小限制(byte)
        //maxUploadSize:整个请求大小限制(byte)
        commonsMultipartResolver.setMaxUploadSizePerFile(10 * 1024 * 1024);
        commonsMultipartResolver.setMaxUploadSize(100 * 1024 * 1024);
        return commonsMultipartResolver;
    }
}


### 2、SpringMVC 容器的生命周期(9 个阶段)


1. 阶段 1:Servlet 容器初始化
2. 阶段 2:创建父容器
3. 阶段 3:创建 springmvc 容器
4. 阶段 4:Servlet 容器中注册 DispatcherServlet
5. 阶段 5:启动父容器:ContextLoaderListener
6. 阶段 6:启动 springmvc 容器:DispatcherServlet#init()
7. 阶段 7:springmvc 容器启动过程中处理@WebMVC
8. 阶段 8:组装 DispatcherServlet 中各种 SpringMVC 需要的组件
9. 阶段 9:销毁 2 个容器


### 3、阶段 1:Servlet 容器初始化


#### 3.1、ServletContainerInitializer


咱们知道 servlet3.0 中新增了一个接口:`ServletContainerInitializer`,这个接口功能特别的牛逼,有了它之后,web.xml 配置文件可要可不要了。



public interface ServletContainerInitializer {
    public void onStartup(Set<Class<?>> c, ServletContext ctx)
        throws ServletException;
}


这个接口的实现类,如果满足下面 2 个条件,Servlet 容器启动的过程中会自动实例化这些类,然后调用他们的 onStartUp 方法,然后我们就可以在这些类的 onStartUp 方法中干活了,在 web.xml 干的所有事情,都可以在这个方法中干,特别强大:



> 
> 1. 这个类必须实现 ServletContainerInitializer 接口,且非抽象类
> 2. 这个类的全类名必须要放在`META-INF/services/javax.servlet.ServletContainerInitializer`这个文件中
> 
> 
> 


#### 3.2、SpringServletContainerInitializer


下面重点来了,springmvc 提供了一个类`SpringServletContainerInitializer`,满足了上面个条件。


![b5e2cd12a8f5245e0fa85a716e6cde5c.png](https://img-blog.csdnimg.cn/img_convert/b5e2cd12a8f5245e0fa85a716e6cde5c.png)


spring-web-5.3.6.jar!\META-INF\services\javax.servlet.ServletContainerInitializer


![cfe152a75ec058aea76cf740a1bc4cd6.png](https://img-blog.csdnimg.cn/img_convert/cfe152a75ec058aea76cf740a1bc4cd6.png)


所以 SpringServletContainerInitializer 的 onStart 方法会 servlet 容器自动被调用


#### 3.3、SpringServletContainerInitializer#onStartup 方法


这个类的源码,大家先看一下,这个类干的事情:



> 
> 1. 类上有@HandlesTypes(WebApplicationInitializer.class) 这个注解,注解的值为`WebApplicationInitializer.class`,所以 onStartup 方法的第一个参数是`WebApplicationInitializer`类型的集合,这个集合由 web 容器自动扫描获取,然后传入进来
> 2. 实例化 WebApplicationInitializer 集合
> 3. 对 WebApplicationInitializer 集合进行排序
> 4. 循环调用 WebApplicationInitializer 的 onStartup 方法
> 
> 
> 



@HandlesTypes(WebApplicationInitializer.class) //@1
public class SpringServletContainerInitializer implements ServletContainerInitializer {

@Override
 public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
   throws ServletException {

List initializers = Collections.emptyList();

if (webAppInitializerClasses != null) {
   initializers = new ArrayList<>(webAppInitializerClasses.size());
   for (Class<?> waiClass : webAppInitializerClasses) {
    // Be defensive: Some servlet containers provide us with invalid classes,
    // no matter what @HandlesTypes says…
    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
      WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
     try {
      initializers.add((WebApplicationInitializer)
        ReflectionUtils.accessibleConstructor(waiClass).newInstance());
     }
     catch (Throwable ex) {
      throw new ServletException(“Failed to instantiate WebApplicationInitializer class”, ex);
     }
    }
   }
  }

if (initializers.isEmpty()) {
   servletContext.log(“No Spring WebApplicationInitializer types detected on classpath”);
   return;
  }

servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
  AnnotationAwareOrderComparator.sort(initializers);
  for (WebApplicationInitializer initializer : initializers) {
   initializer.onStartup(servletContext);
  }
 }

}


下面重点要看`WebApplicationInitializer`接口了。


#### 3.4、WebApplicationInitializer:web 应用初始化


接口比较简单,就一个方法,参数是 servlet 上下文对象,有了个对象,可以干 web.xml 中的一切事情了,比如注册 servlet、filter、监听器等等



public interface WebApplicationInitializer {

void onStartup(ServletContext servletContext) throws ServletException;

}


如下图,看一下类的继承关系,咱们的 MvcInit 就实现了这个接口,所以 MvcInit 的 onStartup 方法会被调费用


![988e006c67479cb1e95d14084db6ed48.png](https://img-blog.csdnimg.cn/img_convert/988e006c67479cb1e95d14084db6ed48.png)


关键代码在这 3 个类中


![148177da348ac47b14dd4920661da108.png](https://img-blog.csdnimg.cn/img_convert/148177da348ac47b14dd4920661da108.png)


#### 3.5、进入 AbstractDispatcherServletInitializer#onStartup 方法



public void onStartup(ServletContext servletContext) throws ServletException {
    super.onStartup(servletContext);
    registerDispatcherServlet(servletContext);
}


**这里是重点:这个方法中干了 4 件事情**



> 
> 1. 创建父容器,只是实例化了,并未启动
> 2. 创建了监听器 ContextLoaderListener,这是一个 ServletContextListener 类型的监听器,稍后会在这个监听器中启动父容器
> 3. 创建 springmvc 容器,只是实例化了,并未启动,启动的事情会在 DispatcherServlet#init 中做,稍后会说
> 4. Servlet 容器中注册 DispatcherServlet
> 
> 
> 


下面,咱们来详细看这几个步骤,把这几个步骤作为阶段来解读。


### 4、阶段 2:创建父容器


父容器可有可无,并不是必须的,为了更好的管理 bean,springmvc 建议我们用父子容器,controller 之外的 bean,比如 service,dao 等,建议放到父容器中,controller 层的和 springmvc 相关的一些 bean 放在 springmvc 容器中,咱们继续。


#### 4.1、过程


`AbstractDispatcherServletInitializer#onStartup`方法中会调用父类的`onStartup`,即`AbstractContextLoaderInitializer#onStartup`,我们进到这个方法中,代码如下图,干了 2 个事情



> 
> 1. 图中编号 ①:创建父容器,只是实例化了,并未启动
> 2. 图中编号 ②:创建了一个监听器 ContextLoaderListener,这是一个 ServletContextListener 类型的监听器,稍后会在这个监听器中启动父容器
> 
> 
> 


![6cd8e179cfead8df1cc9e86fb18933fb.png](https://img-blog.csdnimg.cn/img_convert/6cd8e179cfead8df1cc9e86fb18933fb.png)


下面来分别来细说下上面 2 段代码干的活。


#### 4.2、①:负责创建父容器


`AbstractAnnotationConfigDispatcherServletInitializer#createRootApplicationContext`,只是创建了一个`AnnotationConfigWebApplicationContext`对象,并将父容器配置类 rootConfigClass 注册到容器中,并没有启动这个容器,若 rootConfigClass 为空,父容器不会被创建,所以父容器可有可无。


![a4559bae2da16e6fd604f924643ff02d.png](https://img-blog.csdnimg.cn/img_convert/a4559bae2da16e6fd604f924643ff02d.png)


#### 4.2、②:创建 ContextLoaderListener 监听器


代码如下,创建的时候将父容器对象 rootAContext 传进去了。



ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
//getRootApplicationContextInitializers()返回置为ApplicationContextInitializer数组,是个函数式接口,在父容器初始化的过程中,会作为一个扩展点预留给开发者用
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);


ContextLoaderListener,这是一个 ServletContextListener 类型的监听器,所以在 web 容器启动和销毁的过程中会被调用,如下图,这个监听器干了 2 件事



> 
> 1. contextInitialized 方法:这个方法会在 web 容器启动时被调用,内部负责启动父容器
> 2. 在 contextDestroyed 方法:这个方法会在 web 容器销毁时被调用,内部负责关闭父容器
> 
> 
> 


![004085310864ba72bb537358a82a8654.png](https://img-blog.csdnimg.cn/img_convert/004085310864ba72bb537358a82a8654.png)


### 5、阶段 3&4:创建 springmvc 容器&注册 DispatcherServlet


在回到`AbstractDispatcherServletInitializer#onStartup`,看这个方法的第二行,如下图


![b8b587130bc3c679757e68d88d73555f.png](https://img-blog.csdnimg.cn/img_convert/b8b587130bc3c679757e68d88d73555f.png)


`registerDispatcherServlet`源码如下



protected void registerDispatcherServlet(ServletContext servletContext) {
    //①:DispatcherServlet的servlet名称,默认为:dispatcher
    String servletName = getServletName();

//②:创建springmvc容器
    WebApplicationContext servletAppContext = createServletApplicationContext();

//③:创建DispatcherServlet,注意这里将springmvc容器对象做为参数传递给DispatcherServlet了
    FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
    //设置ApplicationContextInitializer列表,可以对springmvc容器在启动之前进行定制化
    dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());

//④:将 dispatcherServlet 注册到servlet上下文中
    ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
    registration.setLoadOnStartup(1);
    registration.addMapping(getServletMappings());
    registration.setAsyncSupported(isAsyncSupported());

//⑤:注册Filter
    Filter[] filters = getServletFilters();
    if (!ObjectUtils.isEmpty(filters)) {
        for (Filter filter : filters) {
            registerServletFilter(servletContext, filter);
        }
    }
    //⑥:这个方法预留给咱们自己去实现,可以对dispatcherServlet做一些特殊的配置
    customizeRegistration(registration);
}

protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
    return new DispatcherServlet(servletAppContext);
}


### 6、阶段 5:启动父容器:ContextLoaderListener


#### 6.1、过程


上面的`onStartup`方法执行完毕之后,会执行监听器`ContextLoaderListener`的初始化,会进入到他的`contextInitialized`方法中


![3edcdc262245d9f0b9ea91ab6c5e5905.png](https://img-blog.csdnimg.cn/img_convert/3edcdc262245d9f0b9ea91ab6c5e5905.png)


`initWebApplicationContext`源码如下,截取了主要的几行



public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    //this.context就是父容器对象
    ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
    //①:配置及启动父容器
    configureAndRefreshWebApplicationContext(cwac, servletContext);
    //将父容器丢到servletContext中进行共享,方便其他地方获取
    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
}


#### 6.2、代码 ①:配置父容器以及启动父容器



//①:配置及启动父容器
configureAndRefreshWebApplicationContext(cwac, servletContext);


`configureAndRefreshWebApplicationContext`方法关键代码如下



protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    //①:定制上线文,这里主要是遍历ApplicationContextInitializer列表,调用每个ApplicationContextInitializer#initialize方法来对容器进行定制,相当于一个扩展点,可以有程序员自己控制
    customizeContext(sc, wac);
    //②:刷新容器,就相当于启动容器了,此时就会组装里面的bean了
    wac.refresh();
}


`customizeContext`方法,我们进去看一下,这里涉及到了一个新的类,所以有必要去看一下,混个脸熟,源码如下,这是给开发者留的一个扩展点,通过`ApplicationContextInitializer`这个来做扩展,这是一个函数式接口,下面代码会遍历`ApplicationContextInitializer`列表,然后调用其`initialize`方法,我们可以在这个方法中对 spring 上线文进行定制



protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
  List<Class<ApplicationContextInitializer>> initializerClasses =
    determineContextInitializerClasses(sc);

for (Class<ApplicationContextInitializer> initializerClass : initializerClasses) {
        Class<?> initializerContextClass =
            GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
        if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) {
            throw new ApplicationContextException(String.format(
                "Could not apply context initializer [%s] since its generic parameter [%s] " +
                "is not assignable from the type of application context used by this " +
                “context loader: [%s]”, initializerClass.getName(), initializerContextClass.getName(),
                wac.getClass().getName()));
        }
        this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
    }

AnnotationAwareOrderComparator.sort(this.contextInitializers);
    for (ApplicationContextInitializer initializer : this.contextInitializers) {
        initializer.initialize(wac);
    }
}


#### 6.3、ApplicationContextInitializer 接口:容器启动前用来初始化容器


是个函数式接口,在容器启动之前用来对容器进行定制,作为一个扩展点预留给开发者用,父容器和 springmvc 容器都用到了。



@FunctionalInterface
public interface ApplicationContextInitializer {

/**
  * 初始化给定的spring容器
  * @param applicationContext the application to configure
  */
 void initialize(C applicationContext);

}


### 7、阶段 6:启动 springmvc 容器:DispatcherServlet#init()


到目前为止父容器已经启动完毕了,此时 DispatcherServlet 会被初始化,会进入到他的 init()方法中。


#### 7.1、DispatcherServlet 类图


![991cdc1240f1b20ed3754b09ec5d4982.png](https://img-blog.csdnimg.cn/img_convert/991cdc1240f1b20ed3754b09ec5d4982.png)


#### 7.2、HttpServletBean#init()



> 
> 这个方法会调用`initServletBean()`这个方法,其他的先不看
> 
> 
> 


![ae38e03b19ca2a1a1fbb2ebca5c2cc83.png](https://img-blog.csdnimg.cn/img_convert/ae38e03b19ca2a1a1fbb2ebca5c2cc83.png)


#### 7.3、FrameworkServlet#initServletBean



> 
> 提取了关键的代码,就 2 行
> 
> 
> 



@Override
protected final void initServletBean() throws ServletException {
    //初始化springmvc容器,就是启动springmvc容器
    this.webApplicationContext = initWebApplicationContext();
    //这个方法内部是空的,预留给子类去实现的,目前没啥用
    initFrameworkServlet();
}


下面咱们进到`initWebApplicationContext`方法中去。


#### 7.4、FrameworkServlet#initWebApplicationContext



> 
> 关键代码如下,干了 3 件事情:
> 
> 
> 1. 从 servlet 上线文对象中找到父容器
> 2. 为 springmvc 容器指定父容器
> 3. 调用 configureAndRefreshWebApplicationContext 方法配置 springmvc 容器以及启动容器,这个是关键咯
> 
> 
> 



protected WebApplicationContext initWebApplicationContext() {
    //①:从servlet上线文中获取父容器
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
 //②:this.webApplicationContext就是springmvc容器,此时这个对对象不为null,所以满足条件
    if (this.webApplicationContext != null) {
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            //springmvc容器未启动
            if (!cwac.isActive()) {
                //springmvc容器未设置父容器,则给其设置父容器,此时rootContext可能为空,这个没什么关系
                if (cwac.getParent() == null) {
                    cwac.setParent(rootContext);
                }
                //③:配置springmvc容器以及启动springmvc容器
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    //这里省略了一部分代码,如果springmvc采用配置文件的方式会走这部分代码
    …
 //返回容器
    return wac;
}


#### 7.5、FrameworkServlet#configureAndRefreshWebApplicationContext



> 
> 为了让大家看清楚,如下代码,这里只提取了关键代码,主要干了 3 件事情
> 
> 
> 1. 代码 ①:向 springmvc 容器中添加了一个 ContextRefreshListener 监听器,这个监听器非常非常重要,springmvc 容器启动完毕之后会被调用,**会出现在阶段 8 中**
> 2. 代码 ②:给开发者预留的一个扩展点,通过 ApplicationContextInitializer#initialize 方法对容器进行定制
> 3. 代码 ③:启动容器
> 
> 
> 



protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
 //①:向springmvc容器中添加了一个监听器对象,这个监听器特别重要,稍后在
    wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
 //②:扩展点:循环遍历ApplicationContextInitializer列表,调用其initialize方法对容器进行定制
    applyInitializers(wac);
    //③:刷新容器,相当于启动容器
    wac.refresh();
}


### 8、阶段 7:springmvc 容器启动过程中处理@WebMVC


#### 8.1、SpringMVC 配置类被处理


此时 springmvc 容器启动了,此时注意下`MvcConfig`这个类,由于其上有@Conguration 注解,所以会被当做一个配置类被处理,这个类有 2 个非常重要的特征。



> 
> 1. 标注了@EnableWebMvc 注解
> 2. 实现了 WebMvcConfigurer 接口
> 
> 
> 


![d9d007d7cb888ef1d4edc56b7a05c930.png](https://img-blog.csdnimg.cn/img_convert/d9d007d7cb888ef1d4edc56b7a05c930.png)


下面来说说这 2 个特征的作用。


#### 8.2、@EnableWebMvc:配置 springmvc 所需组件


看一下这个注解的源码,如下,重点在于它上面的`@Import(DelegatingWebMvcConfiguration.class)`注解,这个注解的功能不知道的,可以回头去看我的 spring 系列,从头看一遍。


![e6caffc1d224aef39a768f4624a88167.png](https://img-blog.csdnimg.cn/img_convert/e6caffc1d224aef39a768f4624a88167.png)


#### 8.3、进入 DelegatingWebMvcConfiguration 类


代码如下,先注意下面 3 个特征



> 
> 1. 代码编号 ①:标注有@Configuration 注解,说明是一个配置类
> 2. 代码编号 ②:继承了 WebMvcConfigurationSupport 类,这个类中有很多@Bean 标注的方法,用来定义了 springmvc 需要的所有组件
> 3. 代码编号 ③:注入了`WebMvcConfigurer`列表,注意下,我们的 WebConfig 类就实现了 WebMvcConfigurer 这个接口,内部提供了很多方法可以用来对 springmvc 的组件进行自定义配置
> 
> 
> 


![b703184841f78d5e3047edd783e155c5.png](https://img-blog.csdnimg.cn/img_convert/b703184841f78d5e3047edd783e155c5.png)


先来看看 WebMvcConfigurationSupport 这个类。


#### 8.4、WebMvcConfigurationSupport:配置 springmvc 所需所有组件


这个类中会定义 springmvc 需要的所有组件,比如:RequestMapping、HandlerAdapter、HandlerInterceptor、HttpMessageConverter、HandlerMethodArgumentResolver、HandlerMethodReturnValueHandler 等等,所以如果你感觉@WebMVC 注解满足不了你的需求时,你可以直接继承这个类进行扩展。


这个类的源码我就不贴了,截几个图给大家看看


![d326312623c5736feea27dea3e7debfd.png](https://img-blog.csdnimg.cn/img_convert/d326312623c5736feea27dea3e7debfd.png)


#### 8.5、WebMvcConfigurer 接口


这个接口就是我们用来对 springmvc 容器中的组件进行定制的,WebMvcConfigurationSupport 中创建 springmvc 组件的时候,会自动调用 WebMvcConfigurer 中对应的一些方法,来对组件进行定制,比如可以在 WebMvcConfigurer 中添加拦截器、配置默认 servlet 处理器、静态资源处理器等等,这个接口的源码如下



public interface WebMvcConfigurer {

/**
  * 配置PathMatchConfigurer
  */
 default void configurePathMatch(PathMatchConfigurer configurer) {
 }

/**
  * 配置ContentNegotiationConfigurer
  */
 default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
 }

/**
  * 异步处理配置
  */
 default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
 }

/**
  * 配置默认servlet处理器
  */
 default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
 }

/**
  * 配置Formatter
  */
 default void addFormatters(FormatterRegistry registry) {
 }

/**
  * 添加拦截器
  */
 default void addInterceptors(InterceptorRegistry registry) {
 }

/**
  * 静态资源配置
  */
 default void addResourceHandlers(ResourceHandlerRegistry registry) {
 }

/**
  * 跨越的配置
  */
 default void addCorsMappings(CorsRegistry registry) {
 }

/**
  * 配置ViewController
  */
 default void addViewControllers(ViewControllerRegistry registry) {
 }

/**
  * 注册视图解析器(ViewResolverRegistry)
  */
 default void configureViewResolvers(ViewResolverRegistry registry) {
 }

/**
  * 注册处理器方法参数解析器(HandlerMethodArgumentResolver)
  */
 default void addArgumentResolvers(List resolvers) {
 }

/**
  * 注册处理器方法返回值处理器(HandlerMethodReturnValueHandler)
  */
 default void addReturnValueHandlers(List handlers) {
 }

/**
  * 注册http报文转换器(HttpMessageConverter)
  */
 default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
 }

/**
  * 扩展报文转换器
  */
 default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
 }

/**
  * 配置异常解析器(HandlerExceptionResolver)
  */
 default void configureHandlerExceptionResolvers(List resolvers) {
 }

/**
  * 扩展异常解析器(HandlerExceptionResolver)
  */
 default void extendHandlerExceptionResolvers(List resolvers) {
 }

/**
  * 获得验证器

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

s) {
 }

/**
  * 扩展报文转换器
  */
 default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
 }

/**
  * 配置异常解析器(HandlerExceptionResolver)
  */
 default void configureHandlerExceptionResolvers(List resolvers) {
 }

/**
  * 扩展异常解析器(HandlerExceptionResolver)
  */
 default void extendHandlerExceptionResolvers(List resolvers) {
 }

/**
  * 获得验证器

[外链图片转存中…(img-rJePBoF3-1715553819831)]
[外链图片转存中…(img-TsleWWRQ-1715553819832)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值