SpringBoot源码解读与原理分析(六)WebMvc场景的自动装配

本文主要是介绍SpringBoot源码解读与原理分析(六)WebMvc场景的自动装配,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 2.6 WebMvc场景下的自动装配原理
      • 2.6.1 WebMvcAutoConfiguration
      • 2.6.2 Servlet容器的装配
        • 2.6.2.1 EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow
        • 2.6.2.2 BeanPostProcessorsRegistrar(后置处理器的注册器)
        • 2.6.2.3 两个定制器的注册
      • 2.6.3 DispatcherServlet的装配
        • 2.6.3.1 SpringBoot注册Sevlet原生组件
        • 2.6.3.2 DispatcherServlet的注册
      • 2.6.4 SpringWebMvc的装配
        • 2.6.4.1 WebMvcAutoConfigurationAdapter
          • (1)配置消息转换器
          • (2)配置异步支持
          • (3)注册视图解析器
          • (5)配置国际化支持
          • (5)配置RequestContextHolder支持
        • 2.6.4.2 EnableWebMvcConfiguration
          • (1)注册HandlerMapping
          • (2)注册HandlerAdapter
          • (3)静态资源加载配置
    • 2.7 总结

2.6 WebMvc场景下的自动装配原理

了解了SpringBoot的自动装配机制之后,研究一个常见且实用的场景:当项目整合SpringWebMvc后SpringBoot的自动装配都做了什么?

2.6.1 WebMvcAutoConfiguration

引入spring-boot-starter-web依赖后,SpringBoot会进行WebMvc的自动装配,处理的核心是一个叫WebMvcAutoConfiguration的自动配置类。

@Configuration(proxyBeanMethods = false)
// 当前环境必须是WebMvc(Servlet)环境
@ConditionalOnWebApplication(type = Type.SERVLET)
// 当前运行环境的classpath必须有Servlet类、DispatcherServlet类、WebMvcConfigurer类
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// 如果没有自定义的WebMvc配置类,则使用本自动配置
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
// 当前自动配置会在以下几个配置类解析后再处理
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration

由以上源码可知,WebMvcAutoConfiguration自动配置类的生效需要满足以下条件:

  • 当前环境必须是WebMvc(Servlet)环境。引入spring-boot-starter-web依赖后,该条件默认生效。
  • 当前类路径下必须有Servlet类、DispatcherServlet类、WebMvcConfigurer类。
  • 项目中没有自定义的WebMvcConfigurationSupport类或子类,WebMvcAutoConfiguration才会生效。
  • DispatcherServletAutoConfiguration、TaskExecutionAutoConfiguration、ValidationAutoConfiguration会先于WebMvcAutoConfiguration进行解析。

拓展:
DispatcherServlet是前置控制器。拦截匹配的请求,把拦截下来的请求,依据相应的规则分发到目标Controller来处理。

进一步查看源码发现,DispatcherServletAutoConfiguration自动配置类解析之前,ServletWebServerFactoryAutoConfiguration会先解析。

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
// 当前自动配置会在ServletWebServerFactoryAutoConfiguration配置类解析后再处理
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration

所以大体上可以梳理出WebMvc场景的自动装配环节:Servlet容器的装配→DispatcherServlet的装配→WebMvc核心组件的装配。

2.6.2 Servlet容器的装配

嵌入式Servlet容器的装配,导入了几个组件,分别是一个BeanPostProcessorsRegistrar和三个Embedded容器内部类。

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,ServletWebServerFactoryConfiguration.EmbeddedJetty.class,ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration
2.6.2.1 EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow

这三个容器其实是一码事。默认情况下,SpringBoot会整合嵌入式Tomcat(EmbeddedTomcat)作为可独立运行jar文件的Web容器。如果需要切换,只需要在pom文件中移除Tomcat依赖,在添加新的嵌入式Servlet容器依赖。

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId><scope>provided</scope></dependency>
</dependencies>

启动主启动类,会发现嵌入式Servlet容器更换成了Jetty。

2024-01-05 16:04:25.870  INFO 48224 --- [main] o.s.b.web.embedded.jetty.JettyWebServer  : Jetty started on port(s) 8080 (http/1.1) with context path '/'
2024-01-05 16:04:25.898  INFO 48224 --- [main] c.s.springboot.assemble.test02.JettyApp  : Started JettyApp in 3.268 seconds (JVM running for 6.407)

那底层是如何确定该实例化哪个嵌入式Web容器?这是由它们的嵌入式内部类决定的。以EmbeddedTomcat为例:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {@BeanTomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,ObjectProvider<TomcatContextCustomizer> contextCustomizers,ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));return factory;}}

由源码中的@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})可知,只有当前项目的类路径下包含Tomcat类时(引入依赖就会包含),EmbeddedTomcat类才会生效。而EmbeddedTomcat类中注册了一个TomcatServletWebServerFactory对象,它负责创建嵌入式Tomcat容器。(具体如何创建的暂时不讲解)

类似的,只有当前项目的类路径下包含Server类时(引入依赖就会包含),EmbeddedJetty类才会生效。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty

只有当前项目的类路径下包含Undertow类时(引入依赖就会包含),EmbeddedUndertow类才会生效。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow
2.6.2.2 BeanPostProcessorsRegistrar(后置处理器的注册器)

BeanPostProcessors后置处理器,作用是在Bean对象实例化和依赖注入完毕后,在显式调用初始化方法前后添加自定义逻辑。

/*** Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via* {@link ImportBeanDefinitionRegistrar} for early registration.*/
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {private ConfigurableListableBeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {if (beanFactory instanceof ConfigurableListableBeanFactory) {this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;}}@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {if (this.beanFactory == null) {return;}registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",WebServerFactoryCustomizerBeanPostProcessor.class);registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",ErrorPageRegistrarBeanPostProcessor.class);}private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);beanDefinition.setSynthetic(true);registry.registerBeanDefinition(name, beanDefinition);}}}

由以上源码可知,BeanPostProcessorsRegistrar本身是一个ImportBeanDefinitionRegistrar,它注册了两个后置处理器组件:

  • WebServerFactoryCustomizerBeanPostProcessor:负责执行所有webServerFactoryCustomizer(嵌入式Web容器的定制器)
  • ErrorPageRegistrarBeanPostProcessor:负责向嵌入式Web容器注册默认的错误提示页面。
2.6.2.3 两个定制器的注册

ServletWebServerFactoryAutoConfiguration除了使用@Import导入组件,还注册了两个定制器。

public class ServletWebServerFactoryAutoConfiguration {@Beanpublic ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {return new ServletWebServerFactoryCustomizer(serverProperties);}@Bean@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {return new TomcatServletWebServerFactoryCustomizer(serverProperties);}// ...
}

这两个定制器都把ServerProperties作为构造方法的参数传入到定制器中,而ServerProperties定义了有关Web容器的一些配置(如端口、上下文路径、开启SSL等),这些配置对应SpringBoot全局配置文件的server.*部分。

因此,这两个定制器的作用就是将全局配置文件中定义的配置属性实际应用在嵌入式Web容器中,达到“外部配置内部生效”的效果。

2.6.3 DispatcherServlet的装配

2.6.3.1 SpringBoot注册Sevlet原生组件

在解释DispatcherServlet的装配之前,需要了解一下SpringBoot注册Sevlet原生组件的方式。

基于SpringBoot的项目,底层都会采用Servlet 3.0及以上的规范。Servlet 3.0不再使用web.xml,而是使用注解的方式配合Servlet容器扫描完成原生组件的注册。

SpringBoot本身并不默认支持扫描Servlet三大组件,而是提供了两外两种注册方式。

  • Servlet原生组件扫描@ServeltComponentScan
    这种扫描方式适用于自定义的Servlet原生组件。在SpringBoot主启动类上标注@ServeltComponentScan注解后,则会自动扫描主启动类所在包及其子包下的所有Servlet原生组件,要注意的是这些原生组件必须标注@WebServlet、@WebFilter、@WebListener注解(就像@ComponentScan配合@Component注解一样)。
  • 借助辅助注册器RegistrationBean
    这种方式适用于引入项目依赖的jar包中存在Servlet原生组件。由于引入的第三方库中的代码不可修改,因此依靠Servlet原生组件扫描的方式是不现实的。为此SpringBoot引入了辅助注册器RegistrationBean来注册Servlet原生组件。
2.6.3.2 DispatcherServlet的注册

DispatcherServlet的注册在DispatcherServletAutoConfiguration中完成,其核心是两个内部类:

  • DispatcherServletConfiguration
@Configuration(proxyBeanMethods = false)
@Conditional(DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
// 负责注册DispatcherServlet本身
protected static class DispatcherServletConfiguration {@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {DispatcherServlet dispatcherServlet = new DispatcherServlet();// 设置DispatcherServlet的参数以定制化dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());return dispatcherServlet;}@Bean@ConditionalOnBean(MultipartResolver.class)@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)public MultipartResolver multipartResolver(MultipartResolver resolver) {// Detect if the user has created a MultipartResolver but named it incorrectlyreturn resolver;}}
  • DispatcherServletRegistrationConfiguration
// 利用ServletRegistrationBean的子类DispatcherServletRegistrationBean将DispatcherServlet注册到Web容器
@Configuration(proxyBeanMethods = false)
@Conditional(DispatcherServletAutoConfiguration.DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@Import(DispatcherServletAutoConfiguration.DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {// 将DispatcherServlet注册到Web容器DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,webMvcProperties.getServlet().getPath());registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());multipartConfig.ifAvailable(registration::setMultipartConfig);return registration;}}

经过DispatcherServlet的实例化和注册到Web容器,DispatcherServlet的装配工作完成。

2.6.4 SpringWebMvc的装配

WebMvc的装配在WebMvcAutoConfiguration中完成,核心是其中的两个内部类WebMvcAutoConfigurationAdapter和EnableWebMvcConfiguration。

2.6.4.1 WebMvcAutoConfigurationAdapter

WebMvcAutoConfigurationAdapter实现了WebMvcConfigurer接口,重写了大量方法,并注册了一些新的Bean。因此,WebMvcAutoConfigurationAdapter是一个以WebMvc配置为主的配置器。

(1)配置消息转换器
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {this.messageConvertersProvider.ifAvailable((customConverters) -> converters.addAll(customConverters.getConverters()));
}

重写configureMessageConverters方法,目的是配置默认的消息转换器HttpMessageConverter。

消息转换器的作用对象是@RequestBody和@ResponseBody注解标注的Controller方法,分别完成请求体到参数对象的转换以及响应对象到响应体的转换。

默认情况下,SpringBoot在整合WebMvc时,底层会自动依赖Jackson作为JSON支持,所以这里会配置一个MappingJsckson2HttpMessageConverter作为消息转换器的实现。

(2)配置异步支持
public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {// 从容器中找线程池applicationTaskExecutorif (this.beanFactory.containsBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) {Object taskExecutor = this.beanFactory.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);if (taskExecutor instanceof AsyncTaskExecutor) {// 注册异步线程池configurer.setTaskExecutor(((AsyncTaskExecutor) taskExecutor));}}Duration timeout = this.mvcProperties.getAsync().getRequestTimeout();if (timeout != null) {configurer.setDefaultTimeout(timeout.toMillis());}
}

重写configureAsyncSupport方法,目的是配置异步请求的支持。

SpringBoot在底层已经默认准备好了一个异步线程池,支持Controller层使用异步处理的方式接收请求。

线程池在上文提到的TaskExecutionAutoConfiguration自动配置类中创建,bean名称是applicationTaskExecutor。

SpringWebMvc在4.0及以后的版本支持异步请求,即请求处理线程在处理一个请求后,在这个请求调用后端服务期间不阻塞,而是去处理其他的请求。具体的使用方法可以参考网上的一篇博客:SpringMVC创建异步回调请求的4种方式-CSDN-豢龙先生

(3)注册视图解析器
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix(this.mvcProperties.getView().getPrefix());resolver.setSuffix(this.mvcProperties.getView().getSuffix());return resolver;
}@Bean
@ConditionalOnBean(View.class)
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {BeanNameViewResolver resolver = new BeanNameViewResolver();resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);return resolver;
}@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));// ContentNegotiatingViewResolver uses all the other view resolvers to locate// a view so it should have a high precedenceresolver.setOrder(Ordered.HIGHEST_PRECEDENCE);return resolver;
}

InternalResourceViewResolver通过路径前后缀拼接的方式解析逻辑视图名称,常见于原生SpringFramework+SpringWebMvc+Mybatis的项目技术栈中配置,用于处理JSP页面配置,不过SpringBoot默认已经不支持JSP,所以不需要再研究这个视图解析器。

BeanNameViewResolver的一个Bean只能处理一个页面,不实用,因此几乎不再使用。

ContentNegotiatingViewResolver是顶层级的视图解析器,负责将视图解析的工作交由不同的代理ViewResolver类实现,以处理不同的逻辑视图。它的核心工作是中心转发。

(5)配置国际化支持
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {return new FixedLocaleResolver(this.mvcProperties.getLocale());}AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();localeResolver.setDefaultLocale(this.mvcProperties.getLocale());return localeResolver;
}

LocaleResolver是SpringWebMvc针对国际化支持的核心接口,作用解析请求中的语言标志参数或者请求头中的Accept-Language参数,并将解析的参数存放到指定的位置中,通常配合LocaleChangeInterceptor使用。

注意,由该方法的注解@ConditionalOnProperty(prefix = “spring.mvc”, name = “locale”)可知,只有配置了spring.mvc.locale配置项后,LocaleResolver才会被创建。

(5)配置RequestContextHolder支持
@Bean
@ConditionalOnMissingBean({RequestContextListener.class, RequestContextFilter.class})
@ConditionalOnMissingFilterBean(RequestContextFilter.class)
public static RequestContextFilter requestContextFilter() {return new OrderedRequestContextFilter();
}

在实际开发中,我们可能会这样获取HttpServletRequest对象:

HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

这种方式则需要RequestContextHolder的支持,而支撑RequestContextHolder获取的组件就是RequestContextFilter。

2.6.4.2 EnableWebMvcConfiguration

EnableWebMvcConfiguration类中注册了很多WebMvc会用到的核心组件。

(1)注册HandlerMapping
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,@Qualifier("mvcConversionService") FormattingConversionService conversionService,@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {// Must be @Primary for MvcUriComponentsBuilder to workreturn super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,resourceUrlProvider);
}

HandlerMapping处理器映射器的作用是根据请求URL去匹配查找能处理的Handler。目前主流的WebMvc方式都是@RequestMapping注解定义的Handler请求处理器,因此这里直接默认注册了一个RequestMappingHandlerMapping。

(2)注册HandlerAdapter
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,@Qualifier("mvcConversionService") FormattingConversionService conversionService,@Qualifier("mvcValidator") Validator validator) {RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,conversionService, validator);adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());return adapter;
}

处理器适配器HandlerAdapter会拿到HandlerMapping匹配成功的Handler,并用合适的方式执行Handler的逻辑。

使用@RequestMapping注解定义的Handler,其底层负责执行的适配器就是RequestMappingHandlerAdapter。

(3)静态资源加载配置

WebMvc整合页面时必然会有许多的静态资源(如各种.html),addResourceHandlers方法会默认配置几个常用的约定好的静态文件的存放位置:/resources、/static、/webjars/**等。这些路径下的静态文件是可以被直接引用的。

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {super.addResourceHandlers(registry);if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");return;}addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(),this.resourceProperties.getStaticLocations());}
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/","classpath:/resources/", "classpath:/static/", "classpath:/public/" };// ...
}

2.7 总结

2.1 简单介绍组件装配。
2.2-2.4 梳理了SpringFramework的模块装配、条件装配、SPI机制的原理,这三者是自动装配的实现基础。
2.5 梳理了SpringBoot的核心特性:自动装配的机制和原理。
2.6 通过WebMvc场景的自动装配实例,进一步体会自动装配在具体场景中发挥的作用。

本节完,更多内容请查阅分类专栏:SpringBoot源码解读与原理分析

这篇关于SpringBoot源码解读与原理分析(六)WebMvc场景的自动装配的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/695650

相关文章

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B