SpringBoot2.1.5(23)---SpringBoot 开发WEB应用

  SpringBoot非常适合Web应用程序开发。您可以使用嵌入式Tomcat、Jetty、Undertow或Netty创建一个独立的HTTP服务器。大多数Web应用程序使用Spring Boot Starter Web模块快速启动和运行。您还可以选择使用SpringBootStarterWebFlux模块来构建反应式Web应用程序。

SpringWebMVC 框架(通常简称为“SpringMVC”)是一个富的“MVC” 的Web框架。SpringMVC允许您创建特殊的@controller或@restcontroller bean来处理传入的HTTP请求。控制器中的方法通过使用@requestmapping  annotations映射到HTTP。

下面的代码显示了一个典型的@restcontroller,它为JSON数据提供服务:

@RestController
@RequestMapping(value="/users")
public class MyRestController {

	@RequestMapping(value="/{user}", method=RequestMethod.GET)
	public User getUser(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
	List getUserCustomers(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
	public User deleteUser(@PathVariable Long user) {
		// ...
	}

}

SpringBoot默认配置了SpringMVC

引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。
对静态资源的支持,包括对WebJars的支持。
自动注册Converter,GenericConverter,Formatter beans。
对HttpMessageConverters的支持。
自动注册MessageCodeResolver。
对静态index.html的支持。
对自定义Favicon的支持。
字段使用 ConfigurableWebBindingInitializer bean
注意点(重点结论): 
(1)自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(是转发还是重定向)页面); 
(2)ContentNegotiatingViewResolver:组合所有的视图解析器的; 
(3)如何定制自己的视图解析器?我们可以自己给容器中添加一个视图解析器,SpringBoot会自动的将其组合进来;因为从源码分析可以返现ContentNegotiatingViewResolver所组合的视图解析器都是从容器中获取的。

分析一个日期格式化器部分源码:

 @Bean
        //在文件中配置日期格式化的规则,日期格式化器才会生效
        @ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")
        public Formatter dateFormatter() {
            return new DateFormatter(this.mvcProperties.getDateFormat());
        }

从源码中我们可以发现,仅有在配置文件中配置了,SpringBoot配置的日期格式化器才会生效。同时通过格式化器的注解@Bean可以发现该组件在容器中,所以当我们自己需要自定义的格式化器,只需要将其加入容器中即可。(@Bena

(3):再来分析下HttpMessageConverters,其主要作用是SpringMVC用来转换Http请求和响应的;User —> Json 
看看WebMvcAutoConfiguration.class中的函数:

 public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, @Lazy HttpMessageConverters messageConverters, ObjectProvider resourceHandlerRegistrationCustomizerProvider) {
            this.resourceProperties = resourceProperties;
            this.mvcProperties = mvcProperties;
            this.beanFactory = beanFactory;
            this.messageConverters = messageConverters;
            this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
        }

源码方法参数中@Lazy HttpMessageConverters messageConverters可以看出messageConverters是通过容器懒加载获得的,所以也可以得出一个结论:要自定义消息转换器,只需要自己给容器中添加自定义的HttpMessageConverter即可。

(4):ConfigurableWebBindingInitializer : 其主要作用就是 初始化WebDataBinder;将请求的参数转化为对应的JavaBean,并且会结合上面的类型、格式转换一起使用。 
查看WebMvcAutoConfiguration.class中函数源码:
 

protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
            try {
                //从容器中获取
                return (ConfigurableWebBindingInitializer)this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
            } catch (NoSuchBeanDefinitionException var2) {
                return super.getConfigurableWebBindingInitializer();
            }
        }

可以发现ConfigurableWebBindingInitializer是从容器(beanFactory)中获取到的,所以我们可以配置一个ConfigurableWebBindingInitializer来替换默认的,只需要在容器中添加一个我们自定义的转换器即可。

二、扩展SpringMVC
我们再看一段springBoot官方文档关于SpringMvc自动配置的描述。

If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Configuration class of type WebMvcConfigurerAdapter, but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a WebMvcRegistrationsAdapter instance providing such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

其大体翻译就是: 
1. 如果保留Spring Boot MVC特性,你只需添加(拓展)其他的额外的MVC配置(拦截器,格式化处 理器,视图控制器等)。你可以添加自己的WebMvcConfigurerAdapter类型 的 @Configuration 类,而不需要注解@EnableWebMvc 。 
2. 如果希望使用自定义 的 RequestMappingHandlerMapping,RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver,你可以声明一 个WebMvcRegistrationsAdapter实例提供这些组件。 
3. 如果想全面控制Spring MVC,你可以添加自己的@Configuration ,并使 用 @EnableWebMvc 注解。

现在我们尝试拓展一下SpringMvc的功能,要求来一个视图映射,将/hello请求映射视图success中,并且来一个拦截器拦截所有/hello请求。 
这个功能如果是在springmvc中实现是这样的:
 

 
    
    
    
        
            
            
        
    

那根据上面SpringBoot的研究,在SpringBoot中该如何实现这个功能呢?

根据 上面原文的翻译,要拓展一个这样的功能大体的实现步骤是这样的: 
①、编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型; 
②不能标注@EnableWebMvc; 
这样就是既保留了所有的自动配置,也能用我们扩展的配置;

首先找到WebMvcConfigurerAdapter.class源码,发现其实是一个抽象类,我们只需要实现我们要拓展的方法即可:
 

@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {

    //这就是配置视图映射的方法 
     public void addViewControllers(ViewControllerRegistry registry) {
    }

    //这就是配置拦截器的方法
     public void addInterceptors(InterceptorRegistry registry) {
    }
}

下面就来实现我们的拓展(只拓展了视图映射功能,拦截器功能你们自行实现哈):

//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能

@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        //浏览器发送 /hello请求来到 success
        registry.addViewController("/hello").setViewName("success");
    }
}


拓展的原理: 
1)、WebMvcAutoConfiguration是SpringMVC的自动配置类;

​2)、自动配置类在做其他自动配置时会导入@Import(EnableWebMvcConfiguration.class)

  @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})

可以看出EnableWebMvcConfiguration.class是自动配置类的一个内部类。并且继承了DelegatingWebMvcConfiguration

 @Configuration
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration

再来看看DelegatingWebMvcConfiguration源码中的函数setConfigurers

   

   //从容器中获取所有的WebMvcConfigurer
      @Autowired(required = false)
      public void setConfigurers(List configurers) {
          if (!CollectionUtils.isEmpty(configurers)) {
              this.configurers.addWebMvcConfigurers(configurers);
              }
          }
    }


函数中setConfigurers中可以看到,其将容器中所有的WebMvcConfigurer配置都获取到了。 
3)、容器中所有的WebMvcConfigurer都会一起起作用; 
4)、我们的配置类也会被调用; 
最终得到的效果就是:SpringMVC的自动配置和我们的扩展配置都会起作用;

三、全面控制SpringMVC配置
SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了。 
从上面的官方文档翻译可以得知,我们只需要在配置类中添加@EnableWebMvc即可。

如我们将上面拓展的配置加上@EnableWebMvc注解;

@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //浏览器发送 /hello请求来到 success
        registry.addViewController("/hello").setViewName("success");
    }
}



现在可以再启动项目就可以发现,现在springmvc的自动配置都失效了(静态映射、webjars等功能)。

全面控制的原理: 
为什么@EnableWebMvc自动配置就失效了? 
(1)观察其源码:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented

public @interface EnableWebMvc {
}

(2)发现@EnableWebMvc的核心就是导入@Import({DelegatingWebMvcConfiguration.class})而发现DelegatingWebMvcConfiguration又是继承了WebMvcConfigurationSupport类。

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport

(3)再回头看看springBoot对MVC的自动配置类WebMvcAutoConfiguration的源码中:

@Configuration
@ConditionalOnWebApplication( type = Type.SERVLET )
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
//当不存在'WebMvcConfigurationSupport.class'的时候自动配置才生效
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
        .....略
}


从自动配置类WebMvcAutoConfiguration可以看出当且仅当不存在WebMvcConfigurationSupport.class的时候自动配置才生效,但是因为我们将拓展的配置类加上了@EnableWebMvc导致存在类WebMvcConfigurationSupport.class 
(4)因为导入的WebMvcConfigurationSupport只有SpringMVC最基本的功能,而SpringMvc的其他自动配置功能失效,所以被我们的配置全面控制。

四、总结
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(如ViewResolver)将用户配置的和自己默认的组合起来;

2)、用户可以借助添加 WebMvcConfigurerAdapter类型的 @Configuration 类,而不需要注解@EnableWebMvc来拓展Springmvc的自定义配置。

3)、用户可以在配置类加上了@EnableWebMvc注解,实现全面控制SpringMvc配置。
 

你可能感兴趣的:(spring,boot2.1.5)