当前位置: 首页 > news >正文

定制柜需要多少钱/seo点击软件哪个好用

定制柜需要多少钱,seo点击软件哪个好用,公司网站制作注意什么,哈尔滨正规制作网站公司文章目录 2.6 WebMvc场景下的自动装配原理2.6.1 WebMvcAutoConfiguration2.6.2 Servlet容器的装配2.6.2.1 EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow2.6.2.2 BeanPostProcessorsRegistrar(后置处理器的注册器)2.6.2.3 两个定制器的注册 2.6.3 DispatcherServlet的装配2…

文章目录

    • 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场景的自动装配

文章目录 2.6 WebMvc场景下的自动装配原理2.6.1 WebMvcAutoConfiguration2.6.2 Servlet容器的装配2.6.2.1 EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow2.6.2.2 BeanPostProcessorsRegistrar(后置处理器的注册器)2.6.2.3 两个定制器的注册 2.6.3 DispatcherServlet的装配2…...

git恢复rebase过程中遇到权限问题和丢失的提交

文章目录 一、检查丢失的提交是否还在 reflog 中二、创建一个新分支来恢复丢失的提交三、处理权限问题四. 使用 git fsck 查找丢失对象1、创建一个新分支来恢复该提交2、检查和合并提交 五. 介绍git中命令reflog 与 fsck1、git reflog2、git fsck使用场景 一、检查丢失的提交是…...

Spring boot 集成redis

一、使用spring bootspring-boot-starter-data-redis 导入maven包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> spring boot配置文件 spring.re…...

c++ STL系列——(一)概述

引言 在软件开发的世界里&#xff0c;C一直是一门备受青睐的编程语言&#xff0c;特别是在需要高性能和灵活性的场合。而C的标准模板库&#xff08;Standard Template Library&#xff0c;简称STL&#xff09;无疑是这门语言中最强大的工具之一。STL提供了一系列的数据结构和算…...

AI-数学-高中-25-三角函数一图像解决三角函数不等式

原作者视频&#xff1a;【三角函数】【考点精华】1图像解决三角函数不等式问题(基础&#xff09;_哔哩哔哩_bilibili 1.三角函数图像法&#xff1b; 2.不好画图像时&#xff1a;任意角的三角函数图像&#xff0c;在象限中比较&#xff0c;在4个象限中寻找角度的关系。 示例1…...

在Ubuntu上安装JetBrains Toolbox并解决libfuse.so.2依赖问题

在安装JetBrains Toolbox的过程中&#xff0c;我们遇到了libfuse.so.2依赖缺失的问题。这个问题通常发生在尝试运行AppImage格式的程序时&#xff0c;如果系统缺少必要的FUSE&#xff08;Filesystem in Userspace&#xff09;支持。以下是我在解决这个问题并在Ubuntu上成功安装…...

在vscode上传项目到gitee

一、在Gitee上新建一个仓库 Tip&#xff1a;若已经创建过了&#xff0c;直接跳到第二部分看VsCode如何上传代码到Gitee 创建仓库比较简单&#xff0c;下面两张图就是整个过程&#xff0c;这里不在赘述&#xff0c;具体如下&#xff1a; 二、VsCode连接Gitee上创建的仓…...

比较两次从接口获取的数据,并找出变动的字段

问题&#xff1a;有这么一个接口数据&#xff0c;每次会返回这么一个数据: [{Id:1,pending:65,queued:0,completed:0},{Id:2,pending:0,queued:0,completed:0}]&#xff0c;请问再次请求这个接口的时候如何将获取的数据和上一次获取到的数据进行比较&#xff0c;找出变动的字段…...

Java并发基础:LinkedBlockingDeque全面解析!

内容概要 LinkedBlockingDeque提供了线程安全的双端队列实现&#xff0c;它支持在队列两端高效地进行插入和移除操作&#xff0c;同时具备阻塞功能&#xff0c;能够很好地协调生产者与消费者之间的速度差异&#xff0c;其内部基于链表结构&#xff0c;使得并发性能优异&#x…...

Zabbix6.x配置中文界面 解决乱码问题

Zabbix6.x配置中文界面 解决乱码问题 Zabbix6.x界面无法选择中文&#xff0c;通过安装语言包解决。后面也解决了zabbix6中文方块&#xff08;乱码&#xff09;问题。 配置中文语言包 系统中默认没有携带中文语言包&#xff0c;可以通过以下命令查看 localectl list-locales #…...

next项目页面性能调优

next项目页面性能调优 一般来说性能优化可以分为加载时、运行时两部分的优化。 扩展参考链接&#xff1a; 前端性能优化 24 条建议 Webpack 4进阶–从前的日色变得慢 &#xff0c;一下午只够打一次包 Webpack 分包优化首屏加载 参考指标 FCP&#xff08;First Contentful P…...

性能评测|虚拟化和裸金属 K8s 哪个性能更好?

本文重点 整体而言&#xff0c;SKS&#xff08;虚拟机 Kubernetes&#xff09;可以达到裸金属 Kubernetes 性能的 82% – 96%&#xff0c;满足绝大部分场景下生产容器应用的性能需求。更多虚拟化与裸金属 Kubernetes 架构、特性、适用场景与性能对比&#xff0c;欢迎阅读文末电…...

【大厂AI课学习笔记】【1.6 人工智能基础知识】(1)人工智能、机器学习、深度学习之间的关系

6.1 人工智能、机器学习与深度学习的关系 必须要掌握的内容&#xff1a; 如上图&#xff1a;人工智能>机器学习>深度学习。 机器学习是人工智能的一个分支&#xff0c;该领域的主要研究对象是人工智能&#xff0c;特别是如何在经验学习中改进具体算法的性能。 深度学习…...

计算机毕业设计基于的农村蔬菜销售系统SSM

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; vue mybatis Maven mysql5.7或8.0等等组成&#xff0c;B…...

【Chrono Engine学习总结】3-地型terrain

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 1、关于物体材质 在介绍地型之前&#xff0c;要初步了解chrono中关于材质的一些基本概念。 首先&#xff0c;最基本的材质类是ChMaterialSurface,其进一步包括&…...

【Linux】构建模块

&#x1f525;博客主页&#xff1a;PannLZ &#x1f38b;系列专栏&#xff1a;《Linux系统之路》 &#x1f94a;不要让自己再留有遗憾&#xff0c;加油吧&#xff01; 文章目录 构建第一个模块1模块的makefile2内核树内构建3内核树外构建 构建第一个模块 可以在两个地方构建模…...

vscode远程连接失败

目录 解决方案尝试1解决方案尝试2 解决方案尝试1 最近通过vscode一直使用腾讯云的服务器作为远程开发环境&#xff0c;以前一直很好用。 直到最近重装了系统之后&#xff0c;发现vscode没法对云服务器进行连接了&#xff0c;即使在远程主机添加了本地的公钥也不行。直接报错:…...

C#系列-C#访问FTP服务器实现上传下载(8)

FTP Server是什么&#xff1f; FTP Server&#xff08;File Transfer Protocol Server&#xff09;&#xff0c;即文件传输协议服务器&#xff0c;是在互联网上提供文件存储和访问服务的计算机。它依照FTP协议提供服务&#xff0c;专门用来传输文件。 FTP Server允许不同的客…...

django中实现登录

Django中实现登录功能&#xff0c;通常涉及以下几个步骤&#xff1a; 一&#xff1a;实现步骤 1&#xff1a;创建用户模型&#xff1a;Django自带了一个用户认证系统&#xff0c;通常使用内置的User模型来管理用户。你也可以根据需要自定义用户模型。 2&#xff1a;创建登录表…...

【安卓操作系统——讲解】

安卓操作系统 安卓操作系统 安卓操作系统 安卓&#xff08;Android&#xff09;是一种基于Linux内核和其他开源软件的移动操作系统&#xff0c;主要用于触屏移动设备如智能手机和平板电脑。由Andy Rubin等人开发&#xff0c;最初的目的是创建一个先进的操作系统&#xff0c;用…...

Linux发行版全景:选择、使用和未来趋势

1. 引言 Linux操作系统的简介 Linux是一种自由和开源的操作系统内核&#xff0c;由Linus Torvalds在1991年首次发布。随着时间的发展&#xff0c;Linux已经成为世界上最流行的操作系统之一&#xff0c;广泛用于服务器、桌面电脑、移动设备以及嵌入式系统。Linux的主要特点是其…...

STM32 与 ARM 的联系

STM32 和 ARM 是两个不同的概念&#xff0c;但它们之间存在一定的联系。 STM32是一种微控制器产品&#xff0c;由意法半导体&#xff08;STMicroelectronics&#xff09;推出&#xff0c;其内核采用了 ARM Cortex-M 核。ARM 是一家英国芯片设计公司&#xff0c;专注于设计和许可…...

每日五道java面试题之java基础篇(二)

第一题. 为什么说 Java 语⾔“编译与解释并存”&#xff1f; ⾼级编程语⾔按照程序的执⾏⽅式分为编译型和解释型两种。 简单来说&#xff0c;编译型语⾔是指编译器针对特定的操作系统将源代码⼀次性翻译成可被该平台执⾏的机器码&#xff1b;解释型语⾔是指解释器对源程序逐…...

【Linux】Shell编程

Shell编程 目录 Shell编程1.shell基础1.输入重定向 & 输出重定向2.管道3.特殊字符(3.1)通配符(3.2)引号(3.3)注释符(#) 4.别名5.命令历史history 2.Shell脚本Shell脚本的执行方式(1)为脚本文件加上可执行权限,然后在命令行直接输入shell脚本文件名执行。(2)sh shell脚本名(…...

斯巴鲁Subaru EDI需求分析

斯巴鲁Subaru是日本运输集团斯巴鲁公司&#xff08;前身为富士重工&#xff09;的汽车制造部门&#xff0c;以性能而闻名&#xff0c;曾赢得 3 次世界拉力锦标赛和 10 次澳大利亚拉力锦标赛。 斯巴鲁Subaru EDI 需求分析 企业与斯巴鲁Subaru建立EDI连接&#xff0c;首先需要确…...

golang 集成sentry:PostgreSQL

本文介绍通过 pgx库集成sentry&#xff0c; pgx 特点是速度快&#xff0c;可以完全控制&#xff0c;并且支持所有 postgres 数据类型。 pgx地址&#xff1a; https://github.com/jackc/pgx 最简单的接入方式是自定义一个logger&#xff0c; 然后注入到pgx&#xff0c; 完整示…...

ubuntu20.04 安装mysql(8.x)

安装mysql命令 sudo apt-get install mysql-server安装完毕后&#xff0c;立即初始化密码 sudo mysql -u root # 初次进入终端无需密码ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY yourpasswd; # 设置本地root密码设置mysql远程登录 设置远程登录账…...

ChatGPT升级至GPT-4 Turbo:性能升级同时更为经济

ChatGPT升级至GPT-4 Turbo&#xff1a;性能升级同时更为经济 随着技术的进步&#xff0c;ChatGPT迎来了其最新的迭代版本——GPT-4 Turbo。这一最新版本不仅在性能上得到了显著提升&#xff0c;而且在成本效益上也更加引人注目。 性能提升 GPT-4 Turbo带来了诸多改进&#x…...

Android 粒子喷泉动效

一、前言&#xff1a; 在学习open gl es实现动效的时候&#xff0c;打算回顾了一下用普通的2D坐标系实现粒子效果和 open gl 3d 坐标系的区别&#xff0c;以及难易程度&#xff0c;因此本篇以Canvas 2D坐标系实现了一个简单的demo。 粒子动效原理&#xff1a; 粒子动效本质上…...

fast.ai 深度学习笔记(一)

深度学习 2&#xff1a;第 1 部分第 1 课 原文&#xff1a;medium.com/hiromi_suenaga/deep-learning-2-part-1-lesson-1-602f73869197 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;这…...