一、SpringBoot主动装备MVC
1.1 ServletWebServerFactoryAutoConfiguration
@Configuration(proxyBeanMethods = false)
//在主动装备中具有最高优先级履行
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
//导致web注册器和服务器
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
1.1.1 EmbeddedTomcat(默许web服务器)
由条件安装的注解@ConditionalOnClass
能够看到,当时 classpath 下必须有Tomcat
这个类,该装备类才会收效
spring-boot-starter-web
中默许导入的是Tomcat
的依靠
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
1.1.2 EmbeddedJetty
导入需求有Server和Loader
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty {
}
运用Jetty
需求先扫除Tomcat
然后导入Jetty的依靠
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Jetty合适长连接运用,便是聊天类的长连接 -->
<!-- 运用Jetty,需求在spring-boot-starter-web扫除spring-boot-starter-tomcat,因为SpringBoot默许运用tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
1.1.3 EmbeddedUndertow
Undertow它是一个轻量级Web服务器
,但不像传统的 Web 服务器有容器概念,加载一个 Web 运用能够小于 10MB 内存,它供给了对Servlet3.1的支撑(支撑异步
),对Web Socket
彻底支撑,用以满意 Web 运用巨大数量的客户端,它不需求容器,只需经过API即可快速搭建Web服务器
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow {
}
运用undertow
也需求先扫除Tomcat
然后导入undertow的依靠
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
1.1.4 ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar
这儿会注入两个组件ErrorPageRegistrarBeanPostProcessor(处理过错页面)
和WebServerFactoryCustomizerBeanPostProcessor(用于创立Tomcat容器)
创立详情:/post/720838…
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
// ......
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
// 编程式注入组件
registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
}
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
1.2 DispatcherServletAutoConfiguration
这儿注册了MVC的中心组件DispatcherServlet
// 最高装备优先级
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
// Servlet环境下才收效
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";
// 注册DispatcherServlet的装备类
@Configuration
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
// 启用装备文件与Properties的映射
@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
protected static class DispatcherServletConfiguration {
private final HttpProperties httpProperties;
private final WebMvcProperties webMvcProperties;
public DispatcherServletConfiguration(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
this.httpProperties = httpProperties;
this.webMvcProperties = webMvcProperties;
}
// 结构DispatcherServlet
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(this.webMvcProperties.isDispatchTraceRequest());
dispatcherServlet
.setThrowExceptionIfNoHandlerFound(this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setEnableLoggingRequestDetails(this.httpProperties.isLogRequestDetails());
return dispatcherServlet;
}
// 注册文件上传组件
@Bean
@ConditionalOnBean(MultipartResolver.class)
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
public MultipartResolver multipartResolver(MultipartResolver resolver) {
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
}
// 注册DispatcherServletRegistration的装备类
@Configuration
@Conditional(DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@Import(DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {
private final WebMvcProperties webMvcProperties;
private final MultipartConfigElement multipartConfig;
public DispatcherServletRegistrationConfiguration(WebMvcProperties webMvcProperties,
ObjectProvider<MultipartConfigElement> multipartConfigProvider) {
this.webMvcProperties = webMvcProperties;
this.multipartConfig = multipartConfigProvider.getIfAvailable();
}
// 辅助注册DispatcherServlet的RegistrationBean
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
this.webMvcProperties.getServlet().getPath());
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(this.webMvcProperties.getServlet().getLoadOnStartup());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
}
//......
1.3 WebMvcAutoConfiguration
WebMvcConfiguration
中会注入两个中心的组件:处理器适配器
、处理器映射器
以及其他一些相关组件 例如:视图解析器
、视图称号解析器
、国际化组件
等
@Configuration(proxyBeanMethods = false)
//当时环境必须是WebMvc(Servlet)环境
@ConditionalOnWebApplication(type = Type.SERVLET)
//当时运转环境的classpath中必须有Servlet类,DispatcherServlet类,WebMvcConfigurer类
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//假如没有自定义WebMvc的装备类,则运用本主动装备
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
//必须在以下几个组件之后履行
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
.....
//注入视图称号解析器
@Bean
@ConditionalOnBean(View.class)
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
return resolver;
}
//注入视图解析器
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
// ContentNegotiatingViewResolver uses all the other view resolvers to locate
// a view so it should have a high precedence
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
//注入国际化
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
//注入处理器适配器
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
conversionService, validator);
adapter.setIgnoreDefaultModelOnRedirect(
this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
//注入处理器映射器
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
resourceUrlProvider);
}
}
二、RequestMappingHandlerMapping:注册Controller
public void afterPropertiesSet() {
//创立Mapping装备
this.config = new RequestMappingInfo.BuilderConfiguration();
//解析恳求中的途径
this.config.setUrlPathHelper(getUrlPathHelper());
//途径匹配校验器
this.config.setPathMatcher(getPathMatcher());
//是否支撑后缀弥补,默许为true
this.config.setSuffixPatternMatch(useSuffixPatternMatch());
//是否增加"/"后缀,默许为true
this.config.setTrailingSlashMatch(useTrailingSlashMatch());
//是否选用mediaType匹配形式,比方.json/.xml形式的匹配,默许为false
this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
//mediaType处理类
this.config.setContentNegotiationManager(getContentNegotiationManager());
//调用父类进行HandlerMethod的注册作业
super.afterPropertiesSet();
}
父类AbstractHandlerMethodMapping
#afterPropertiesSet
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
处理没有被署理的Bean(Bean称号不是scopedTarget.最初)
被@Scope
标示的目标,假如署理形式是jdk或者cglib署理的话,会在spring容器中发生2个bean,一个是署理的bean,一个是原始的bean,原始的bean的beanName被ScopedProxyUtils
命名为:scopedTarget.xx:
private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget.";
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//处理候选Bean
processCandidateBean(beanName);
}
}
//打印mapper注册的数量日志
handlerMethodsInitialized(getHandlerMethods());
}
获取被@Controller
或 @RequestMapping
注解标示的Bean
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
//判别是否有@Controller 或 @RequestMapping 注解
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
解析办法
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
//2.1 解析挑选办法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
//2.2 注册办法映射
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
2.1 MethodIntrospector.selectMethods:解析挑选办法
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final Map<Method, T> methodMap = new LinkedHashMap<>();
Set<Class<?>> handlerTypes = new LinkedHashSet<>();
Class<?> specificHandlerType = null;
//不是署理类
if (!Proxy.isProxyClass(targetType)) {
specificHandlerType = ClassUtils.getUserClass(targetType);
handlerTypes.add(specificHandlerType);
}
//获取一切接口类
handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
//获取具体的办法
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
//挑选办法--》会进入回调函数
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
//将办法作为key 封装的RequestMappingInfo作为value放入map中
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
这儿会进入外层的办法
{
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 1.1.1 创立办法级别的RequestMappingInfo /testMethod
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 1.1.1 创立类级别的RequestMappingInfo /test
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
//拼接办法上的 @RequestMapping途径 /test/testMethod
if (typeInfo != null) {
info = typeInfo.combine(info);
}
// 1.1.2 拼接途径前缀
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).build().combine(info);
}
}
return info;
}
2.1.1 createRequestMappingInfo:创立MappingInfo
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
//获取办法上的@RequestMapping注解
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
//获取办法判别器
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
//假如有@RequestMapping注解包装成RequestMappingInfo
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
将@RequestMapping注解信息包装成RequestMappingInfo
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}
2.1.2 getPathPrefix:拼接途径前缀
private Map<String, Predicate<Class<?>>> pathPrefixes = new LinkedHashMap<>();
String getPathPrefix(Class<?> handlerType) {
//获取途径前缀
for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
if (entry.getValue().test(handlerType)) {
String prefix = entry.getKey();
if (this.embeddedValueResolver != null) {
prefix = this.embeddedValueResolver.resolveStringValue(prefix);
}
return prefix;
}
}
return null;
}
WebMvcAutoConfiguration
在初始化的时分设置了pathPrefixes
2.2 注册办法映射
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
注册Mapping
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
//注册Mapping
super.registerHandlerMethod(handler, method, mapping);
updateConsumesCondition(mapping, method);
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
这儿会将Mapping注册进urlLookup
、mappingLookup
和registry
中
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
public void register(T mapping, Object handler, Method method) {
// 读写锁加锁
this.readWriteLock.writeLock().lock();
try {
// 将Controller的类型和Controller中的办法包装为一个HandlerMethod目标
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
// 将RequestMappingInfo和Controller的目标办法存入Map中
this.mappingLookup.put(mapping, handlerMethod);
// 将注解中的映射url和RequestMappingInfo存入Map
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
// 将Controller目标办法和跨域装备存入Map
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
// uri 映射 HandlerMethod封装的MappingRegistration目标,存入Map中
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
三、DispatcherServlet#onRefresh:初始化web容器(第一次恳求)
第一次恳求进来是会进行Servlet初始化
,Servlet的init()
办法会被调用。
进入 DispatcherServlet
中,发现并没有该办法,那么肯定在它集成的父类上。
DispatcherServlet
承继于 FrameworkServlet
,成果还是没找到,持续找它的父类 HttpServletBean
。
@Override
public final void init() throws ServletException {
//获取装备web.xml中的参数
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
//要点:一个空办法,模板形式,子类FrameworkServlet,重写了它
initServletBean();
}
FrameworkServlet
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("Initializing Servlet '" + getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
//要点:初始化WebApplicationContext
this.webApplicationContext = initWebApplicationContext();
//一个空办法,能够供给给今后的子类复写,做一些初始化的工作,暂时没有被复写
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
//省掉无关代码...
}
initWebApplicationContext()
办法是初始化 WebApplicationContext
的,而它集成于 ApplicationContext
,所以它也是一个IoC容器。
所以 FrameworkServlet
类的责任是将 Spring
和 Servler
进行一个关联。
这个办法,除了初始化WebApplicationContext外,还调用了一个 onRefresh()
办法,又是模板形式,空办法,让子类复写进行逻辑处理,例如子类DispatcherServlet
重写了它
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
//有参数结构办法,传入webApplicationContext目标,就会进入该判别
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
//还没初始化过,容器的refresh()还没有调用
if (!cwac.isActive()) {
//设置父容器
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
//获取ServletContext,之前经过setAttribute设置到了ServletContext中,现在经过getAttribute获取到
wac = findWebApplicationContext();
}
if (wac == null) {
//创立WebApplicationContext,设置环境environment、父容器,本地资源文件
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
//刷新,也是模板形式,空办法,让子类重写进行逻辑处理,而子类DispatcherServlet重写了它
onRefresh(wac);
}
}
//用setAttribute(),将容器设置到ServletContext中
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
//WebApplicationContext
public interface WebApplicationContext extends ApplicationContext {
//...
}
DispatcherServlet
履行刷新web容器
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
初始化SpringMVC九大组件
protected void initStrategies(ApplicationContext context) {
//3.1 初始化multipart类型文件解析器
initMultipartResolver(context);
//3.2 初始化用户区域解析器(多语言、国际化)
initLocaleResolver(context);
//3.3 初始化主题解析器
initThemeResolver(context);
//3.4 初始化映射器(处理Controller的办法和url映射联系)
initHandlerMappings(context);
//3.5 初始化适配器,多样写法Controller的适配处理,完成最终回来都是ModelAndView
initHandlerAdapters(context);
//3.6 初始化反常处理器
initHandlerExceptionResolvers(context);
//3.7 初始化视图转发
initRequestToViewNameTranslator(context);
//3.8 初始化视图解析器,将ModelAndView保存的视图信息,转换为一个视图,输出数据
initViewResolvers(context);
//3.9 初始化映射处理器
initFlashMapManager(context);
}
3.1 初始化multipart类型文件解析器
MultipartResolver 用于处理文件上传
,当收到恳求时 DispatcherServlet 的checkMultipart() 办法会调用 MultipartResolver 的isMultipart()
办法判别恳求中是否包括文件。假如恳求数据中包括文件,则调用MultipartResolver 的resolveMultipart()
办法对恳求的数据进行解析,然后将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest (承继了HttpServletRequest) 目标中,最终传递给 Controller
初始化时会直接从容器中获取MultipartResolver
类型的Bean
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
}
3.2 初始化用户区域解析器(多语言、国际化)
LocaleResolver
其主要效果在于根据不同的用户区域展现不同的视图
,而用户的区域
也称为Locale
,该信息是能够由前端直接获取的。经过这种方法,能够完成一种国际化
的意图,比方针对美国用户能够供给一个视图,而针对我国用户则能够供给另一个视图。
初始化时会直接从容器中获取LocaleResolver
类型的Bean
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
}
3.3 初始化主题解析器
设置整个体系的主题。主题便是体系的整体款式或风格,可经过Spring MVC框架供给的主题(theme)设置运用的整体款式风格,提高用户体会。Spring MVC的主题便是一些静态资源的调集,即包括款式及图片,用来控制运用的视觉风格。
private void initThemeResolver(ApplicationContext context) {
try {
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
}
3.4 初始化映射器
适配器
、反常处理器
、视图转发
、视图解析器
、映射处理器
初始化流程都相似,都是从容器中获取然后进行排序。
//处理器映射调集
@Nullable
private List<HandlerMapping> handlerMappings;
//一个开关,标识是否获取一切的处理器映射,假如为false,则搜索指定名为的 handlerMapping 的 Bean实例
private boolean detectAllHandlerMappings = true;
//指定的Bean的称号
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
private void initHandlerMappings(ApplicationContext context) {
//清空调集
this.handlerMappings = null;
//一个开关,默许为true,设置为false,才走else的逻辑
if (this.detectAllHandlerMappings) {
//要点:在容器中找到一切HandlerMapping
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
//找到了,进行排序,保证顺序
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
//指定搜索指定名为 handlerMapping 的 HandlerMapping 实例
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
//也找不到映射联系,设置一个默许的
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
//装备文件名
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
//从装备文件中获取装备的组件,其他组件找不到时,也是调用这个办法进行默许装备
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
//...
}
}