SpringMVC系列这里都基于纯注解的方式。而要实现纯注解,就是要替代原本的web.xml
和springmvc.xml
两个配置文件的内容。
不扫描Controller类
@ComponentScan(value = "com.wml",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
})
public class SpringRootConfig {
}
扫描Controller类
@ComponentScan(value = "com.wml",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
public class WebMvcConfig {
}
这里相当于web.xml,后面会加载到。
public class WebAppInit extends AbstractAnnotationConfigDispatcherServletInitializer {
//Spring父容器
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{SpringRootConfig.class};
}
//SpringMVC配置子容器
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebMvcCOnfig.class};
}
//DispatcherServlet的映射信息
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
return super.getServletFilters();
}
}
@Configuration
@EnableWebMvc
public class AppConfig extends WebMvcConfigurationSupport {
@Autowired
private MyInterceptor userInterceptor;
//配置视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/items/**").excludePathPatterns("/items/get/**");
super.addInterceptors(registry);
}
//还有其他的一些配置,如转换器等
}
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("======preHandle=========");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("========postHandle======");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("========afterCompletion======");
}
}
这样就可以完全取代xml配置了,还有Controller省略没写。
在Servlet 3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果能发现的话,就会用它来配置Servlet容器。
在setvlet容器启动时,会根据SPI服务发现的设计,在spring-web-5.1.3.RELEASE/META-INF/services/javax.servlet.ServletContainerInitializer
中,加载里面的类:
org.springframework.web.SpringServletContainerInitializer
,而该类实现了ServletContainerInitializer
接口,如下:
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer{}
因此,该类就会在启动时进行实例化,调用到其唯一的onStartup方法,但是,其类上还有个注解@HandlesTypes(WebApplicationInitializer.class)
,因此会在调用方法前,会先收集该实现该注解中的接口的类,也就是上面我们自己定义的WebAppInit
类,该类顶级父类就是WebApplicationInitializer
,会在onStartup
方法中作为参数传入。
如下:
参数webAppInitializerClasses
就是我们的WebAppInit
类
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
.....
}
}
}
。。。。
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
//调用WebApplicationInitializer实现类的onStartup方法
initializer.onStartup(servletContext);
}
}
这个方法最终就会调用WebApplicationInitializer
实现类的onStartup
方法:
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
//注册DispatcherServlet
registerDispatcherServlet(servletContext);
}
这里会先调用其父类的onStartup
方法,
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
在该类中完成监听器的创建。
protected void registerContextLoaderListener(ServletContext servletContext) {
//代码1:创建spring上下文对象
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
//创建监听器上下文,并将spring上下文添加进去
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
//将监听器上下文加入servlet上下文
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
createRootApplicationContext创建Spring上下文
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
//注册到上下文
context.register(configClasses);
return context;
}
else {
return null;
}
}
在该方法中,通过调用getRootConfigClasses
就可以拿到我们在WebAppInit
类中实现的该方法,返回SpringRootConfig
类class对象,该类中我们配置了扫描的包,然后就通过基于注解的上下文对象注册到Spring上下文中。
接着会将Spring的上下文对象注册到监听器上下文中,再将监听器上下文注册到servlet上下文中。
回到上面,调用完super.onStartup
后,接着调用registerDispatcherServlet
,在该方法中注册DispatcherServlet
看后面具体流程分析
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return null or empty");
//代码1:创建springmvc的上下文,注册了MvcContainer类
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");
//代码2:创建DispatcherServlet
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
//代码3:将dispatcherServlet添加到servlet上下文
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
if (registration == null) {
throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
"Check if there is another servlet registered under the same name.");
}
//如果值为正整数或者0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载
registration.setLoadOnStartup(1);
//这里会调用到我们实现的方法获取DispatcherServlet的映射信息
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
// 获取过滤器,该方法默认为空,可重写它加入我们自己的过滤器
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
代码1:createServletApplicationContext
这里会调用到我们自己实现的getServletConfigClasses
方法,如下:
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebMvcConfig.class};
}
WebMvcConfig
类中,我们配置了扫描带Controller注解的类,在这里将该类注册到上下文中。
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
Class<?>[] configClasses = getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
context.register(configClasses);
}
return context;
}
代码2:createDispatcherServlet
然后创建DispatcherServlet
,将mvc的上下文传进去,再将DispatcherServlet
对象添加到servlet上下文中.
到这里onStartup方法就执行完毕了,完成了向servlet
容器中添加监听器ContextLoaderListener
和DispatcherServlet
的任务。
监听器上下文就是上面的ContextLoaderListener
,因为实现了ServletContextListener
,servlet容器启动时,就会触发它的contextInitialized
方法:
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
......
try {
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
//主要看这里
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
//将上下文对象WebApplicationContext添加到servletContext中
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
return this.context;
}
....
}
这里主要关注configureAndRefreshWebApplicationContext
方法,然后就是会将WebApplicationContext
上下文对象设置到servletContext。
该方法只要看最后,就是调用了refresh
方法,该方法我们都知道,会初始化Spring容器,实例化,依赖注入等,就会将前面配置监听器时,要扫描的非Controller注解的类进行实例化注册,完成Spring上下文的创建。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
...........
wac.setServletContext(sc);
....
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);
wac.refresh();
}
前面配置DispatcherServlet时,会在servlet容器启动时启动,触发生命周期中的init
方法,位于HttpServletBean
类中:
public final void init() throws ServletException {
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
............
//调用子类FrameworkServlet的实现
initServletBean();
}
protected final void initServletBean() throws ServletException {
...
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
...
}
//看这里
protected WebApplicationContext initWebApplicationContext() {
//代码1:刚刚通过servletContext.setAttribute将Listener监听器加载的spring容器添加到了servlet容器,这里就可以获得到了
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// DispatcherServlet的spring上下文
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
//这里将spring容器作为自己的父容器,这样当需要注入某个bean时就可以从父上下文中获取
cwac.setParent(rootContext);
}
//代码2:这里dispatcherServlet启动子容器
configureAndRefreshWebApplicationContext(cwac);
}
}
}
....
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
//这里会对相关组件进行初始化
onRefresh(wac);
}
}
。。。。。
return wac;
}
这部分主要做了两个工作:
getBean
流程。到这里取代web.xml的配置解析就结束了。
接着看看如何取代springmvc.xml的:
我们在AppConfig
类中,定义了EnableWebMvc
注解:
@Configuration
@EnableWebMvc
public class AppConfig extends WebMvcConfigurationSupport {}
如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
在该类中引入了DelegatingWebMvcConfiguration
配置类:
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
//拿到AppConfig类:AppConfig$$EnhancerBySpringCGLIB..
this.configurers.addWebMvcConfigurers(configurers);
}
}
@Override
protected void configurePathMatch(PathMatchConfigurer configurer) {
this.configurers.configurePathMatch(configurer);
}
@Override
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
this.configurers.configureContentNegotiation(configurer);
}
@Override
protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {
this.configurers.configureAsyncSupport(configurer);
}
@Override
protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
this.configurers.configureDefaultServletHandling(configurer);
}
@Override
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
this.configurers.addResourceHandlers(registry);
}
@Override
protected void addCorsMappings(CorsRegistry registry) {
this.configurers.addCorsMappings(registry);
}
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
@Override
protected void configureViewResolvers(ViewResolverRegistry registry) {
this.configurers.configureViewResolvers(registry);
}
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
this.configurers.addArgumentResolvers(argumentResolvers);
}
@Override
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
this.configurers.addReturnValueHandlers(returnValueHandlers);
}
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.configurers.configureMessageConverters(converters);
}
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
this.configurers.extendMessageConverters(converters);
}
@Override
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.configurers.configureHandlerExceptionResolvers(exceptionResolvers);
}
@Override
protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.configurers.extendHandlerExceptionResolvers(exceptionResolvers);
}
@Override
@Nullable
protected Validator getValidator() {
return this.configurers.getValidator();
}
@Override
@Nullable
protected MessageCodesResolver getMessageCodesResolver() {
return this.configurers.getMessageCodesResolver();
}
}
该类都是通过WebMvcConfigurerComposite
对象configurers调用实现,而该对象在该方法中获取:
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
//拿到AppConfig类:AppConfig$$EnhancerBySpringCGLIB..
this.configurers.addWebMvcConfigurers(configurers);
}
}
这个参数configurers
就是我们的配置类AppConfig
,而该方法是通过@Autowired(required = false)
注入的,因此依赖注入时,会先检查依赖的WebMvcConfigurer
,对其进行实例化,这时就是解析我们的配置类AppConfig
进行实例化依赖注入。
DelegatingWebMvcConfiguration
继承自WebMvcConfigurationSupport
,在该类中,就完成了许多组件的bean实例化,RequestMappingHandlerMapping
、PathMatcher
、HandlerMapping
、HandlerAdapter
和BeanNameUrlHandlerMapping
等等,每个组件都是通过@Bean
注入的:
在实例化时会调用许多我们实现的钩子方法,如拦截器、跨域配置等。
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
//代码1:添加拦截器
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
......
return mapping;
}
如代码1:添加拦截器
protected final Object[] getInterceptors() {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
//这里是个钩子方法,会调用到我们自己定义的添加拦截器的方法【AppConfig中定义】
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
等等就不列举了,但这里需要注意的是,当我们发送请求时,要定位到某个具体的方法,而url和方法的映射关系肯定不会在发送请求的时候才建立,一定是在启动的时候就建立完毕的了。
RequestMappingHandlerMapping
的顶级接口实现了InitializingBean
接口,该类的afterPropertiesSet
方法会在bean实例化后调用【bean声明周期的知识】,而对url和方法的映射关系建立就是在这里进行的。
AbstractHandlerMethodMapping#afterPropertiesSet
public void afterPropertiesSet() {
initHandlerMethods();
}
//这里会遍历上下文中的beanName,进行注册映射关系
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//主要看这里
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
processCandidateBean
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
....
//如果类上面有@Controller注解或者@RequestMapping注解
if (beanType != null && isHandler(beanType)) {
//建立uri和method的映射关系
detectHandlerMethods(beanName);
}
}
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || //如果有Controller注解
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));//如果有RequestMapping注解
}
找到有Controller
和RequestMapping
注解的bean,因为这两个注解的类中才有 url 开始进行具体的映射建立。
protected void detectHandlerMethods(Object handler) {
//拿到class对象
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
//这里的map,key就是类中所有有RequestMappint注解的方法对象
// value就是RequestMapping注解属性封装的对象
//也就是将这两者建立了映射关系
//代码1:selectMethods
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
...
});
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//建立uri和方法的各种映射关系,反正一条,根据uri要能够找到method对象
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
代码1: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;
......
handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
//doWithMethods中会拿到当前Controller类中所有的方法,然后遍历调用方法的doWith方法,也就是这里的lambada表示
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
//拿到当前方法
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
//如果方法上面有@RequestMapping注解,则进行封装返回,result就是封装后的注解对象,调用外层的lambada表达式
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
//将方法对象和注解封装对象简历映射关系
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
该方法主要就是遍历当前类中的所有方法,然后调用metadataLookup.inspect
,也就是外层的lambada表达式,对有RequestMapping注解的方法,封装其注解的属性信息返回,得到T result
,然后将方法对象和其封装的注解属性对象,放到map中建立关系映射,返回该map。
外层的lambada表达式会调用getMappingForMethod
:
如果该方法有@RequestMapping
注解,就将注解信息封装成RequestMappingInfo
中,如果类中也有该注解,则同样的方式封装类上的注解信息,然后将这两个信息合并,因为我们知道一个url,是将其类上的url和方法上的url拼接成的。
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//判断是否有@RequestMapping注解,然后注解里面的内容封装成对象
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//类上面的@RequestMapping注解也封装成对象
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//把方法上面的注解属性结合到类上面的RequestMappingInfo对象中
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).build().combine(info);
}
}
return info;
}
这里可以看一下其封装注解属性的实现:
用到了建造者设计模式一一将其属性进行构造封装
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();
}
回到上面的detectHandlerMethods
方法,接着会调用下面的循环:
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//建立uri和方法的各种映射关系,反正一条,根据uri要能够找到method对象
registerHandlerMethod(handler, invocableMethod, mapping);
});
具体会调用register
方法:
HandlerMethod
中RequestingMappingInfo
,和HandlerMethod
建立映射RequestingMappingInfo
建立映射public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
//创建HandlerMethod对象,其实
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
//建立uri对象和handlerMethod的映射关系
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
//url和RequestMappingInfo进行映射
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
//将CrossOrigin注解属性封装成CorsConfiguration
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
//建立映射关系
this.corsLookup.put(handlerMethod, corsConfig);
}
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
总之就是将各种信息进行映射,包括
url和handlerMethod的映射、
url和requestMapping的映射、
handlerMethod和跨域配置对象的映射等。
但我们只要知道容器启动时,这些url和方法的映射以及各种映射已经建立完毕,在SpingMVC调用时,就可以直接拿到。
后面我们会讲SpringMVC的调用流程。SpringMVC流程总结、源码详解