docs/Spring全家桶/SpringMVC源码分析/SpringMVC的Demo与@EnableWebMvc注解.md
Ϊ˸õط springmvc Դ룬Ҫһ springmvc demo demo Ƿ spring-learn ģ顣
tomcat 8 ֮tomcat ṩ˶аҪʱֱͿˣӦ gradle :
optional("org.apache.tomcat.embed:tomcat-embed-core")
spring Ŀ build.gradle УѾ tomcat-embed-core-9.0.29.jar spring-learn ģʱָ汾
package org.springframework.learn.mvc.demo01;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Component
@ComponentScan("org.springframework.learn.mvc.demo01")
@EnableWebMvc
public class MvcConfig {
}
Ϊ MvcConfigָĿİɨ·Լͨ @EnableWebMvc mvc ܡ
WebApplicationInitializerpackage org.springframework.learn.mvc.demo01;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MvcConfig.class);
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
}
}
spring ṩһӿ WebApplicationInitializerʵָýӿʱ onStartup(...) д spring applicationContextȻ servelet ע DispatcherServlet
package org.springframework.learn.mvc.demo01;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping("/hello")
public String hello() {
System.out.println("hello!!!");
return "hello world!";
}
}
һ controllerһַ "hello world".
ˣ
package org.springframework.learn.mvc.demo01;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
public class MvcDemo01Main {
public static void main(String[] args) throws Exception {
Tomcat tomcat = new Tomcat();
Connector connector = new Connector();
connector.setPort(8080);
connector.setURIEncoding("UTF-8");
tomcat.getService().addConnector(connector);
Context context = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
LifecycleListener lifecycleListener = (LifecycleListener)
Class.forName(tomcat.getHost().getConfigClass())
.getDeclaredConstructor().newInstance();
context.addLifecycleListener(lifecycleListener);
tomcat.start();
tomcat.getServer().await();
}
}
main УҪ tomcat
У£
̨
ҳ淵أ
Կһ springmvc Ŀʹˡ
servlet 3.0 淶¹ϵ springmvc Ŀһ⼸ xml ļ
web.xmlservlet ļ web ʱIJԼ servlet/listener/filter;spring.xmlspring ļҪ spring bean.spring-mvc.xmlspringmvc ļ mvc ص beanļϴص beanͼ beancontroller ·ȡĿʱȼ web.xml web.xml м spring ã spring
demo УǷֲ ûЩã web.xml ļûУô web Ŀôأ
servlet 3.0 ֮ṩһ spi 淶spring ʵ£
spring-web ģ /src/main/resources/META-INF/services/ ļ£ļ javax.servlet.ServletContainerInitializerorg.springframework.web.SpringServletContainerInitializer
org.springframework.web.SpringServletContainerInitializer ʵ servlet 淶// @HandlesTypes עservlet淶ʾ webAppInitializerClass Ϊ WebApplicationInitializer.class
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
/*
* д ServletContainerInitializer onStartup
* Ҫʵ spring ṩ WebApplicationInitializer.classȻִ onStartup
*
* Set<Class<?>> webAppInitializerClasses еΪ WebApplicationInitializer.class
* @HandlesTypes עָ
*/
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
// ʹ÷ʵ WebApplicationInitializer ʵ࣬ӵ initializers
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
...
}
}
}
}
servletContext.log(initializers.size() + " ...");
// ʵOrderdӿڣע @Order ע⣬ʵ PriorityOrderd ӿ
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
// WebApplicationInitializer ʵonStartup
initializer.onStartup(servletContext);
}
}
}
WebApplicationInitializer ʵ demo ж WebApplicationInitializer ʵ֣package org.springframework.learn.mvc.demo01;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
public class MyWebApplicationInitializer implements WebApplicationInitializer {
/*
* spring Ŀ
*/
@Override
public void onStartup(ServletContext servletContext) {
// spring ApplicationContext
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MvcConfig.class);
// DispatcherServlet servlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
}
}
ִй£
ɴˣspring ˡ
demo Уͨ @EnableWebMvc mvc ܣôעʲôأǽ EnableWebMvc ࣺ
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
Կעͨ @Import ע DelegatingWebMvcConfiguration.class DelegatingWebMvcConfiguration:
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
...
}
@Configuration ע⣬Ǹ̳࣬е WebMvcConfigurationSupport``WebMvcConfigurationSupport Ϊ "mvc ֧"ô mvc صõġ
Ϊ˸õطȽܼࣺ
DelegatingWebMvcConfiguration @EnableWebMvc ࣬ WebMvcConfigurationSupport ࣬д WebMvcConfigurationSupport ṩ÷
/*
* @ConfigurationǸ
* extends WebMvcConfigurationSupport̳WebMvcConfigurationSupport
*/
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
// WebMvcConfigurerComposite WebMvcConfigurer ϣᵽ
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
/**
* configurers
* @Autowiredע⣬ʾspringеWebMvcConfigurer bean Ϊ
* configurersֵ Ȼø÷
*/
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
/**
* PathMatch
*/
@Override
protected void configurePathMatch(PathMatchConfigurer configurer) {
// WebMvcConfigurerComposite ķ
this.configurers.configurePathMatch(configurer);
}
// ÷Ҳǵ WebMvcConfigurerComposite Ӧķõ
...
}
WebMvcConfigurerComposite``WebMvcConfigurer ϣ
/**
* ʵ WebMvcConfigurer
*/
class WebMvcConfigurerComposite implements WebMvcConfigurer {
// delegatesΪ WebMvcConfigurer ļ
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
/*
* DelegatingWebMvcConfiguration#setConfigurers
* ǰѴconfigurersӵdelegates(ҲWebMvcConfigurer)
*/
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
/**
* ʱdelegates(ҲWebMvcConfigurer)õ
* еÿһWebMvcConfigurer
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.configurePathMatch(configurer);
}
}
// ƣʡ
...
}
WebMvcConfigurerspringmvc ýӿڣṩ˷dz
public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {
}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
...
}
WebMvcConfigurationSupportspringmvc ֧
/**
* ʵawareӿ
*/
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
//================= XxxAware ӿڵķ =================
@Override
public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void setServletContext(@Nullable ServletContext servletContext) {
this.servletContext = servletContext;
}
//================= @Bean spring bean =================
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(...) {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
// getInterceptors(...) ȡ interceptors¿
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
mapping.setContentNegotiationManager(contentNegotiationManager);
// getCorsConfigurations(...) ȡCorsã¿
mapping.setCorsConfigurations(getCorsConfigurations());
// getPathMatchConfigurer(...) ȡPathMatchã¿
PathMatchConfigurer configurer = getPathMatchConfigurer();
...
return mapping;
}
...
//================= get xxx ÷springṩĬãԶ =======
// ȡ interceptors
protected final Object[] getInterceptors(
FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider) {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
// ÷ interceptor¿
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
// ȡCors
protected final Map<String, CorsConfiguration> getCorsConfigurations() {
if (this.corsConfigurations == null) {
CorsRegistry registry = new CorsRegistry();
// ÷ CorsMapping¿
addCorsMappings(registry);
this.corsConfigurations = registry.getCorsConfigurations();
}
return this.corsConfigurations;
}
// ȡPathMatch
protected PathMatchConfigurer getPathMatchConfigurer() {
if (this.pathMatchConfigurer == null) {
this.pathMatchConfigurer = new PathMatchConfigurer();
configurePathMatch(this.pathMatchConfigurer);
}
return this.pathMatchConfigurer;
}
...
//================= ÷ʵ =================
// Զ Interceptorʵ
protected void addInterceptors(InterceptorRegistry registry) {
}
// Զ CorsMappingʵ
protected void addCorsMappings(CorsRegistry registry) {
}
// Զ PathMatch
protected void configurePathMatch(PathMatchConfigurer configurer) {
}
...
}
ԿķΪࣺ
XxxAware ķXxxAware ӿ spring ṩbean ʼʱص@Bean עķ spring bean bean ʱ getXxxgetXxx ȡ÷ڸ÷У spring ṩĬãԼ addXxx/configureXxx ԶãaddXxx/configureXxx ʵ֣ springmvc Զáܽ 4 Ĺϵ
ĸĹϵ@EnableWebMvc ִ̾һĿȻˣܽ£
@EnableWebMvc spring DelegatingWebMvcConfiguration
DelegatingWebMvcConfiguration а @Autowired עķ setConfigurers(List<WebMvcConfigurer>) spring bean лִУΪȡ WebMvcConfigurer bean õ DelegatingWebMvcConfiguration У
DelegatingWebMvcConfiguration ̳ WebMvcConfigurationSupport spring bean лᴦ WebMvcConfigurationSupport @Bean עķַȽ϶࣬ requestMappingHandlerMapping()``mvcPathMatcher ȣЩ smvc Ĺ
ڴ WebMvcConfigurationSupport @Bean עķʱ getXxx() ȡãð spring ṩĬüԶãgetXxx() WebMvcConfigurationSupport ṩ
ڵ WebMvcConfigurationSupport#getXxx() ȡԶʱ addXxx()/configureXxx()÷ WebMvcConfigurationSupport ǿշ (Ҳ DelegatingWebMvcConfiguration) ṩյ÷ʽִе 2 ȡ WebMvcConfigurer addXxx()/configureXxx()
ͼʾ
springmvc ܣԶʱǿô:
ʽ 1ʹ @EnableWebMvc ע mvc ܣʵ WebMvcConfigurerԶ
// ʹ@EnableWebMvcעmvc
@Component
@EnableWebMvc
public class MvcConfig {
...
}
// ʵ WebMvcConfigurerԶ
@Component
public class MyWebMvcConfigurer implements WebMvcConfigurer {
// дWebMvcConfigurerԶ
}
ʽ 2ʵ WebMvcConfigurationSupport ࣬де÷
@Component
public class MyWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
// д÷Զ
}
ַʽʵ WebMvcConfigurer ԶþͲЧˣԶֻ WebMvcConfigurationSupport á
springmvc ṩЩأ WebMvcConfigurer ṩķ
configurePathMatch·configureContentNegotiationЭconfigureAsyncSupportconfigureDefaultServletHandlingĬϾ̬ԴaddFormattersעԶתaddInterceptorsaddResourceHandlersԴaddCorsMappingsCORSaddViewControllersͼתconfigureViewResolversͼaddArgumentResolversԶ巽addReturnValueHandlersԶ巵ؽconfigureMessageConvertersϢתػḲĬע HttpMessageConverterextendMessageConvertersϢתһԶ HttpMessageConverter.configureHandlerExceptionResolvers쳣תextendHandlerExceptionResolvers쳣תgetValidator:getMessageCodesResolverҪֻҪдط ɡ
WebMvcConfigurationSupport Щ Bean @Bean עķ£
public RequestMappingHandlerMapping requestMappingHandlerMapping(...)public PathMatcher mvcPathMatcher()public UrlPathHelper mvcUrlPathHelper()public ContentNegotiationManager mvcContentNegotiationManager()public HandlerMapping viewControllerHandlerMapping(...)public BeanNameUrlHandlerMapping beanNameHandlerMapping(...)public RouterFunctionMapping routerFunctionMapping(...)public HandlerMapping resourceHandlerMapping(...)ResourceUrlProvider mvcResourceUrlProvider()public HandlerMapping defaultServletHandlerMapping()public RequestMappingHandlerAdapter requestMappingHandlerAdapter(...)public HandlerFunctionAdapter handlerFunctionAdapter()public FormattingConversionService mvcConversionService()public Validator mvcValidator()public CompositeUriComponentsContributor mvcUriComponentsContributor(...)public HttpRequestHandlerAdapter httpRequestHandlerAdapter()public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter()public HandlerExceptionResolver handlerExceptionResolver(...)public ViewResolver mvcViewResolver(...)HandlerMappingIntrospector mvcHandlerMappingIntrospector()Щ springmvc õһЩľݾͲչˡ
ݱȽӣṩһ springmvc demoȻ demo 0 xml ԭ (Ҳ servlet 3.0 淶Ž @EnableWebMvc Ĺܣؽ WebMvcConfigurationSupport á
ԭӣhttps://my.oschina.net/funcy/blog/4696657 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע