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

这篇具有很好参考价值的文章主要介绍了SpringBoot源码解读与原理分析(六)WebMvc场景的自动装配。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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 {

    @Bean
    TomcatServletWebServerFactory 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;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        if (beanFactory instanceof ConfigurableListableBeanFactory) {
            this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
        }
    }

    @Override
    public 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 {

    @Bean
    public 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 incorrectly
        return 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) {
    // 从容器中找线程池applicationTaskExecutor
    if (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 precedence
    resolver.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 work
    return 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源码解读与原理分析文章来源地址https://www.toymoban.com/news/detail-831787.html

到了这里,关于SpringBoot源码解读与原理分析(六)WebMvc场景的自动装配的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot源码分析(1)--@SpringBootApplication注解使用和原理/SpringBoot的自动配置原理详解

    springboot原理索引 SpringBoot源码分析(1)–@SpringBootApplication注解使用和原理/SpringBoot的自动配置原理详解 SpringBoot源码分析(2)–SpringBoot启动源码(万字图文源码debug讲解springboot启动原理) 本文主要讲解@SpringBootApplication注解使用和原理。 源码基于spring-boot-2.2.13.RELEASE进行讲解 主要是

    2024年02月13日
    浏览(41)
  • Spring Boot源码解读与原理分析

      最近机缘巧合之下,读到了 LinkedBear 编写的《Spring Boot源码解读与原理分析》这本书,本人花了一周的时间认真研读了一下这本书,真的是受益匪浅,特此推荐给大家,好书不容错过啊。 LinkedBear 是一名资深的Java开发工程师,常年致力于底层技术的研究,同时也通过技术

    2024年02月08日
    浏览(46)
  • 【框架源码】SpringBoot核心源码解读之启动类源码分析

    首先我们要先带着我们的疑问,spring boot是如何启动应用程序?去分析SpringBoot的启动源码。 我们在新建SpringBoot项目时,核心方法就是主类的run方法。 SpringApplication.run(ArchWebApplication.class, args) 我们点击run方法进入到源码中,这块传入的了一个我们当前程序主类的类对象以及主

    2024年02月06日
    浏览(41)
  • 《Spring Boot源码解读与原理分析》书籍推荐

    Spring Boot 1.0.0 早在2014年就已经发布,只不过到了提倡“降本增效”的今天,Spring Boot才引起了越来越多企业的关注。Spring Boot是目前Java EE开发中颇受欢迎的框架之一。依托于底层Spring Framework的基础支撑,以及完善强大的特性设计,Spring Boot已成为业界流行的应用和微服务开发

    2024年02月14日
    浏览(35)
  • 拆解Spring boot:Springboot为什么如此丝滑而简单?源码剖析解读自动装配

    🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 《Spring 狂野之旅:从入门到入魔》 🚀 本专栏带你从Spring入门到入魔   这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.csdn

    2024年03月23日
    浏览(42)
  • springboot 原理分析之自动配置

             Condition 是在 Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean 操作。比如说,只有满足某一个条件才能创建这个 Bean ,否则就不创建。         SpringBoot 是如何知道要创建哪个 Bean 的?比如 SpringBoot 是如何知道要创建  RedisTemplate 

    2024年01月19日
    浏览(36)
  • SpringBoot自动配置原理简单分析

    说明:在SpringBoot项目中,我们添加了许许多多的注解,这些注解提高了开发效率。这是因为SpringBoot在项目启动时,帮我们自动装配了大量的Bean对象,可以通过分析源码查看自动装配的大致原理。 进入到启动类中的@SpringBootApplication注解中,该注解里面有七个注解,上面四个

    2024年02月09日
    浏览(41)
  • SpringBoot自动装配原理及分析

    在使用SpringBoot的时候,会自动将Bean装配到IOC容器中。例如我们在使用Redis数据库的时候,会引入依赖spring-boot-starter-data-redis。在引入这个依赖后,服务初始化的时候,会将操作Redis需要的组件注入到Ioc容器中进行后续使用。 自动装配的大致过程如下: 获取到组件(spring-boo

    2024年01月21日
    浏览(41)
  • Springboot中SpringSecurity自动装配原理,源码级别绝对详细

    (1)Springboot有一个自动配置类 SecurityFilterAutoConfiguration , SecurityFilterAutoConfiguration 只要当项目中引入了SpringSecurity的相关jar包就会被自动加载。装载这个类是干嘛的呢? (2)如下图, SecurityFilterAutoConfiguration 自动配置类主要用于,当存在名字叫做\\\"springSecurityFilterChain\\\"的bea

    2024年02月05日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包