手動配置檢視解析器流程分析

羅羅的1024發表於2020-10-14

springboot有一些類是自動幫我們配置好的,那麼我們想自動配置一些類該怎麼配置呢?
以檢視解析器為例,進入mvc的自動配置類

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
    public static final String DEFAULT_PREFIX = "";
    public static final String DEFAULT_SUFFIX = "";
    private static final String[] SERVLET_LOCATIONS = new String[]{"/"};
    
	@Bean
	@ConditionalOnBean({ViewResolver.class})
	@ConditionalOnMissingBean(
	name = {"viewResolver"},
	     value = {ContentNegotiatingViewResolver.class}
	  )
	public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
	   ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
	   resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
	   resolver.setOrder(-2147483648);
	   return resolver;
	}
關鍵類 ContentNegotiatingViewResolver
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean {
    @Nullable
    private ContentNegotiationManager contentNegotiationManager;
    private final ContentNegotiationManagerFactoryBean cnmFactoryBean = new ContentNegotiationManagerFactoryBean();
    private boolean useNotAcceptableStatusCode = false;
    @Nullable
    private List<View> defaultViews;
    @Nullable
    private List<ViewResolver> viewResolvers;
    .......
	省略
	.......

	 protected void initServletContext(ServletContext servletContext) {
	 	//從上下文IOC容器中獲取所有的檢視解析器
        Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
        ViewResolver viewResolver;
        if (this.viewResolvers == null) {
            this.viewResolvers = new ArrayList(matchingBeans.size());
            Iterator var3 = matchingBeans.iterator();

            while(var3.hasNext()) {
                viewResolver = (ViewResolver)var3.next();
                if (this != viewResolver) {
                    this.viewResolvers.add(viewResolver);
                }
            }
        } else {
            for(int i = 0; i < this.viewResolvers.size(); ++i) {
                viewResolver = (ViewResolver)this.viewResolvers.get(i);
                if (!matchingBeans.contains(viewResolver)) {
                    String name = viewResolver.getClass().getName() + i;
                    this.obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolver, name);
                }
            }
        }

        AnnotationAwareOrderComparator.sort(this.viewResolvers);
        this.cnmFactoryBean.setServletContext(servletContext);
    }

在候選的檢視解所有檢視中選擇最好的檢視進行返回

 public View resolveViewName(String viewName, Locale locale) throws Exception {
        RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
        Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
        List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
        if (requestedMediaTypes != null) {
        	//返回所有的候選檢視
            List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
            //選擇最好的檢視進行返回
            View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
            if (bestView != null) {
                return bestView;
            }
        }

遍歷所有的檢視解析器,通過檢視名( viewName )找到所有可以被檢視解析器解析的檢視 ,加入到候選的檢視candidateViews中

private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {
        List<View> candidateViews = new ArrayList();
        if (this.viewResolvers != null) {
            Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
            Iterator var5 = this.viewResolvers.iterator();

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

自定義一個檢視解析器試試

@Configuration
public class MyViewResolver  {

    @Bean
    public ViewResolver myselfViewResolver() {
        return new LuoViewResolver();
    }

    private static class  LuoViewResolver implements ViewResolver{
        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }
}

執行檢視有沒有加入容器中
在這裡插入圖片描述

相關文章