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

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置