拓展springmvc原理详解

拓展springmvc原理

springboot自定义配置采用了策略模式,配置同样的组件采用不同的实现方法,因此必定有一个接口封装了一系列“算法”,这个接口就是WebMvcConfigurer
在这里插入图片描述
可以重写的方法:
在这里插入图片描述
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean {实现了视图解析器接口的类,就可以看成是一个视图解析器,那么问题来了,我们也要做一个实现视图解析器接口的类,就要知道它的规则,规则应该怎么找呢?因此,我们即使在ContentNegotiatingViewResolver很难找到规则,可以到它的父类或者实现的接口去找,这里选了ViewResolver:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.web.servlet;

import java.util.Locale;
import org.springframework.lang.Nullable;

public interface ViewResolver {
    @Nullable
    View resolveViewName(String var1, Locale var2) throws Exception;
}

然后就可以到ContentNegotiatingViewResolver找到resolveViewName方法:

 if (requestedMediaTypes != null) {
            List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
            View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
            if (bestView != null) {
                return bestView;
            }

这个方法获取候选视图,得到最好的视图,如何获取候选视图:
进入方法getCandidateViews:这个方法遍历所有的视图解析器,获取视图,封装到view,view添加到候选视图candidateViews,最后返回。


            while(var5.hasNext()) {
                ViewResolver viewResolver = (ViewResolver)var5.next();
                View view = viewResolver.resolveViewName(viewName, locale);
                if (view != null) {
                    candidateViews.add(view);
                }

                Iterator var8 = requestedMediaTypes.iterator();

                while(var8.hasNext()) {
                    MediaType requestedMediaType = (MediaType)var8.next();
                    List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
                    Iterator var11 = extensions.iterator();

                    while(var11.hasNext()) {
                        String extension = (String)var11.next();
                        String viewNameWithExtension = viewName + '.' + extension;
                        view = viewResolver.resolveViewName(viewNameWithExtension, locale);
                        if (view != null) {
                            candidateViews.add(view);
                        }
                    }
                }
            }
        }

        if (!CollectionUtils.isEmpty(this.defaultViews)) {
            candidateViews.addAll(this.defaultViews);
        }

        return candidateViews;

如何自定义视图解析器:

@Configuration
//@EnableWebMvc这个不能标注,否则就会被springboot的mvc全面接管
public class MyConfiger implements WebMvcConfigurer {
    
    //将自定义视图解析器交给spring管理
    @Bean
    public  ViewResolver myViewResolver(){
        return new MyViewResolver();
    }
    
    //自定义视图解析器
    public static class MyViewResolver implements ViewResolver{

        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }

}

那么如何得知我们配置的视图解析器配置成功呢?
答案:利用dispatcherServlet(前端控制器),因为所有请求都会经过前端控制器,前端控制器把请求发给前端控制器,进入DispatcherServlet的doService方法的this.doDispatch(request, response);方法,所有的请求和响应都经过这里


    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

因此在这里断点
在这里插入图片描述
结果:其中thymeleaf是我们导入thymeleaf启动器后有的,而MyConfiger是我们自己配置的,其余都是默认的。
在这里插入图片描述

实现WebMvcConfigurer中的方法

@Configuration
//@EnableWebMvc这个不能标注,否则就会被springboot的mvc全面接管
public class MyConfiger implements WebMvcConfigurer {


    //视图跳转
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/xlh").setViewName("yyds");
    }
}

在这里插入图片描述
为什么拓展mvc不能导入@EnableWebMvc

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

@EnableWebMvc导入了DelegatingWebMvcConfiguration.class

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport

进入WebMvcAutoConfiguration类中

 @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
        private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
        private final ResourceProperties resourceProperties;
        private final WebMvcProperties mvcProperties;
        private final ListableBeanFactory beanFactory;
        private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
        final WebMvcAutoConfiguration.ResourceHandlerRegistration

进入@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})中EnableWebMvcConfiguration.class

 public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
        private final ResourceProperties resourceProperties;
        private final WebMvcProperties mvcProperties;

进入DelegatingWebMvcConfiguration,下面方法加入容器中所有的WebMvcConfigurer

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

    }

所以说@EnableWebMvc从容器中获取所有的WebMvcConfig。

回归正题,WebMvcAutoConfiguration有效的条件:@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})不存在

@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {

而@EnableWebMvc会导入DelegatingWebMvcConfiguration,DelegatingWebMvcConfiguration继承WebMvcConfigurationSupport,因此自动配置部分失效,但是自定义拓展的(例如手动导入的thymeleaf还能用)还能用:
在这里插入图片描述
在这里插入图片描述
总结:
1.只要看到xxxConfiguration,一定是springmvc拓展功能。
2.WebMvcAutoConfiguration、xxxConfiguration以及自己定义的拓展的xxxConfiguration层级关系:
WebMvcAutoConfiguration是自动配置类,WebMvcAutoConfiguration包含xxxConfiguration,自己定义的拓展的xxxConfiguration和xxxConfiguration同层级,都是组件,里面的是写组件功能(方法),都实现WebMvcConfig接口,WebMvcConfig接口里面有一些webmvc的一些没有实现的功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fire king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值