首页 > 其他分享 >Spring Boot-Spring MVC自动装配原理

Spring Boot-Spring MVC自动装配原理

时间:2024-09-30 15:23:40浏览次数:8  
标签:web Spring adapter Boot springframework MVC 设置 configurer

说明

在非Spring Boot项目中我们要使用Spring MVC 要做很多繁琐的配置,配置DispatcherServlet、配置RequestMapping 配置RequestMappingAdapter

当我们使用Spring Boot项目只需要引入以下依赖就完成了整个自动Spring MVC的装配实现开箱即用

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>

完成自动装配的核心依赖在

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>2.0.5.RELEASE</version>
      <scope>compile</scope>
    </dependency>

我们查看依赖数

这个包里面汇集了常用框架的spring boot的自动装配的整合方案,关于我们Spring MVC的自动装配在web下的servlet包下的org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

我们来跟一下源码看看是如何完成自动装配的吧这个类里面有一系列的Spring MVC组件初始化我们主要关注 

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration

 

EnableWebMvcConfiguration类主要继承了spring-webmvc提供的WebMvcConfigurationSupport 来与spring 整合

 

RequestMappingHandlerAdapter组件自动装配

主要解释WebMvcConfigurer完成自定义配置原理 这里举例了一个例子,后续更多自定义配置都是围绕WebMvcConfigurer

<1>

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter

  @Bean
        public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
            //<1-1>交给父类方法进行初始化
            RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
            adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
            return adapter;
        }

<1-1>

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerAdapter

 @Bean 
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        // <1-1-1>创建 RequestMappingHandlerAdapter 实例
        RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
        
        //<1-1-2>设置内容协商管理器
        adapter.setContentNegotiationManager(mvcContentNegotiationManager());
        
        // 设置消息转换器
        adapter.setMessageConverters(getMessageConverters());
        
        // 设置 Web 绑定初始化器
        adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
        
        // 设置自定义参数解析器
        adapter.setCustomArgumentResolvers(getArgumentResolvers());
        
        // 设置自定义返回值处理器
        adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

        // 如果存在 Jackson 依赖,则设置 JSON 视图处理建议
        if (jackson2Present) {
            adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
            adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
        }

        // 创建并配置异步支持配置器
        AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
        configureAsyncSupport(configurer);
        
        // 如果配置了任务执行器,则设置到 adapter 中
        if (configurer.getTaskExecutor() != null) {
            adapter.setTaskExecutor(configurer.getTaskExecutor());
        }
        
        // 如果配置了超时时间,则设置到 adapter 中
        if (configurer.getTimeout() != null) {
            adapter.setAsyncRequestTimeout(configurer.getTimeout());
        }
        
        // 设置可调用拦截器
        adapter.setCallableInterceptors(configurer.getCallableInterceptors());
        
        // 设置延迟结果拦截器
        adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

        // 返回配置好的 RequestMappingHandlerAdapter 实例
        return adapter;
    }

<1-1-1>

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#createRequestMappingHandlerAdapter

    protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
        return new RequestMappingHandlerAdapter();
    }

<1-1-2>

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#mvcContentNegotiationManager

    @Bean
    public ContentNegotiationManager mvcContentNegotiationManager() {
        if (this.contentNegotiationManager == null) {
            ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
            configurer.mediaTypes(getDefaultMediaTypes());
            //<1-1-2-1>交给子类DelegatingWebMvcConfiguration 也就是WebMvcConfigurationSupport的父类
            configureContentNegotiation(configurer);
            this.contentNegotiationManager = configurer.buildContentNegotiationManager();
        }
        return this.contentNegotiationManager;
    }

<1-1-2-1>

WebMvcConfigurer 就是我们使用spring boot进行自定义配置原理

       @Autowired(
        required = false
    )
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }

    }
    //委托给 WebMvcConfigurer 进行自定义配置
    protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        this.configurers.configureContentNegotiation(configurer);
    }

RequestMappingHandlerMapping自定装配

<1>

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

    @Bean
        @Primary
        public RequestMappingHandlerMapping requestMappingHandlerMapping() {
            //<1-1>委托给父类处理
            return super.requestMappingHandlerMapping();
        }

<1-1>

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerMapping

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
    // 创建 RequestMappingHandlerMapping 实例
    RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();

    // 设置映射顺序
    mapping.setOrder(0);

    //<1-1-1>设置拦截器
    mapping.setInterceptors(getInterceptors());

    // 设置内容协商管理器
    mapping.setContentNegotiationManager(mvcContentNegotiationManager());

    // 设置跨域配置
    mapping.setCorsConfigurations(getCorsConfigurations());

    // 获取路径匹配配置器
    PathMatchConfigurer configurer = getPathMatchConfigurer();

    // 获取是否使用后缀模式匹配的配置
    Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
    if (useSuffixPatternMatch != null) {
        // 设置是否使用后缀模式匹配
        mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
    }

    // 获取是否使用注册的后缀模式匹配的配置
    Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
    if (useRegisteredSuffixPatternMatch != null) {
        // 设置是否使用注册的后缀模式匹配
        mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
    }

    // 获取是否使用尾部斜杠匹配的配置
    Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
    if (useTrailingSlashMatch != null) {
        // 设置是否使用尾部斜杠匹配
        mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
    }

    // 获取 URL 路径帮助器
    UrlPathHelper pathHelper = configurer.getUrlPathHelper();
    if (pathHelper != null) {
        // 设置 URL 路径帮助器
        mapping.setUrlPathHelper(pathHelper);
    }

    // 获取路径匹配器
    PathMatcher pathMatcher = configurer.getPathMatcher();
    if (pathMatcher != null) {
        // 设置路径匹配器
        mapping.setPathMatcher(pathMatcher);
    }

    // 返回配置好的 RequestMappingHandlerMapping 实例
    return mapping;
}

<1-1-1>

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors

protected final Object[] getInterceptors() {
        if (this.interceptors == null) {
            //初始化InterceptorRegistry
            InterceptorRegistry registry = new InterceptorRegistry();
            //<1-1-1-1>交给子类进行自定义设置
            addInterceptors(registry);
            registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
            registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
            //获取自定义设置的拦截器
            this.interceptors = registry.getInterceptors();
        }
        return this.interceptors.toArray();
    }

<1-1-1-1>

    @Autowired(
        required = false
    )
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }

    }
    
 protected void addInterceptors(InterceptorRegistry registry) {
//调用WebMvcConfigurer完成拦截器注入 this.configurers.addInterceptors(registry); }

来看看我们要自定义拦截器如何做的WebMvcConfigurer 最终形成了闭环

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final Logger logger = LoggerFactory.getLogger(WebConfig.class);

    @Autowired
    private LoginAuthenticationFilter loginAuthenticationFilter;

    @Autowired
    private AuthorizationInterceptor authorizationInterceptor;

    @Autowired
    private LogHandlerInterceptor logHandlerInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**");
        registry.addInterceptor(logHandlerInterceptor).addPathPatterns("/**");
    }

}

总结

知道了Spring Boot整合Spring MVC的入口点,并且举例了围绕WebMvcConfigurer进行的初始化,后续我们对相关其他配置初始化可以跟这里源码

标签:web,Spring,adapter,Boot,springframework,MVC,设置,configurer
From: https://www.cnblogs.com/LQBlog/p/18441921

相关文章

  • pbootcms模板指定内容标签调用
    为了更好地理解和使用PbootCMS中的指定内容标签,可以将相关的控制参数和可用的内容标签整理成表格形式。这样可以更清晰地展示每个参数的作用和用法。控制参数参数说明必填id=*内容的ID号,用于控制输出的内容,适用于单页或列表页内容。是scode=*单页的分类编码......
  • PbootCMS设置当前站点模板,模板子目录,黑白名单,敏感词过滤等
    在PbootCMS中,后台操作涉及多个配置项,包括更换模板路径、配置后台模板子目录、配置后台黑名单和白名单以及敏感词过滤。以下是详细的步骤和解释。后台操作更换模板路径进入【基础内容】在后台管理界面左侧菜单栏中点击“基础内容”。选择【站点信息】在“基础内容”......
  • Spring boot中使用实现Redis Lua计数器
    Springboot中使用实现RedisLua计数器在SpringBoot中使用RedisLua脚本实现计数器,可以通过以下步骤来完成。这个示例将展示如何使用Lua脚本在Redis中安全地增加计数器的值。步骤1:添加依赖首先,确保你的pom.xml文件中包含了SpringDataRedis和Lettuce的依赖:<dependency>......
  • pbootcms在线升级后伪静态分页url变成?page=xx问题
    在PbootCMS中,如果你想在网站首页右侧或列表页左侧调用特定栏目的标签(tags),可以使用 {pboot:tags} 标签来实现。下面详细介绍如何使用该标签以及具体参数的含义。使用 {pboot:tags} 标签语法html {pboot:tagsscode=2,5,8num=50}[tags:text]{/pboot:tags}参......
  • 实现在 PbootCMS 网站首页右侧或列表页左侧调用特定栏目的标签,并确保标签显示和链接正
    假设你想在网站首页右侧或列表页左侧调用特定栏目的标签,可以使用以下代码:HTML模板代码<!--调用指定栏目的标签--><divclass="tags-list">{pboot:tagsscode=2,5,8num=50}<ahref="[tags:url]"><span>[tags:text]</span></a>{/pboot:......
  • PbootCMS默认面包屑导航样式修改及自定义的设置方法
    在使用PbootCMS建站时,如果需要对系统默认的面包屑(breadcrumb)标签样式进行修改,可以通过自定义参数来实现。下面详细介绍如何使用 {pboot:position} 标签,并自定义相关的参数。自定义面包屑标签基本语法{pboot:position}[position:breadcrumb]{/pboot:position}......
  • PbootCMS出现登录失败,表单提交校验失败等情况怎么办?
    在使用PbootCMS过程中,可能会遇到一些登录问题,例如表单提交校验失败、登录界面锁定以及数据库目录权限写入不足等问题。以下是对这些问题的详细解决方案。一、表单提交校验失败问题描述:登入失败,表单提交校验失败。解决方法:检查服务器环境确认服务器环境是否符合Pboot......
  • pbootcms内容详情页标签调用
    在PbootCMS中,内容详情页标签用于展示文章的详细信息。以下是一张表格,列出了常用的内容详情页标签及其功能和用法。PbootCMS内容详情页标签一览表标签名功能描述用法示例[content:id]获取文章ID[content:id][content:title]获取文章标题[content:title][......
  • PBOOTCMS的水印功能如何使用?pbootcms设置的水印为何没生效?
    在PbootCMS中,水印功能主要用于给新上传的图片添加水印。如果你发现开启了水印功能但前端仍然没有水印,可能是因为以下几个原因:只对新上传的图片生效:水印功能仅对新上传的图片生效,之前上传的图片不会自动加上水印。水印配置未生效:可能是因为水印配置没有正确设置或生效。图片......
  • pbootcms列表如何置顶文章,istop不管用怎么办?
    在PbootCMS中,如果你想在列表中将某篇文章置顶,但发现后台设置了置顶后前端没有效果,这通常是由于前端调用标签的方式不正确。下面详细介绍如何使用PbootCMS的标签来实现文章置顶功能。调用置顶文章的方法1.只调用置顶的文章如果你只想调用置顶的文章,可以使用以下标签:{pb......