文章目录
RequestMappingHandlerMapping
- HandlerMapping是SpringMVC的策略组件之一,称作处理器映射器,其作用是根据请求获取到对应的处理器,是HandlerMapping的实现类。
- RequestMappingHandlerMapping是HandlerMapping接口的一个实现类,用于根据请求来获取处理器对象(实际是获取HandlerExecutionChain),按照调试过程发现真正处理的HandlerMapping实现类是RequestMappingHandlerMapping,因此作为HandlerMapping接口的典型实现类来分析它。
一、初始化
1.1 继承关系
- RequestMappingHandlerMapping经过几层继承关系,最终是继承自AbstractHandlerMapping这个HandlerMapping的抽象实现类。因为继承关系复杂,我们按照主流程来看看关键代码。主要是初始化扫描Handler处理器、获取Handler处理器扫描拦截器。
- 这里的Handler处理器抽象来说就是指我们处理请求的方法,比如我们代码中写的@PostMapping的方法,但是在框架内部可以回进行一定的包装以保存方法的更多信息。
1.2 Handler初始化
- RequestMappingHandlerMapping实现了InitializingBean接口,对应的afterPropertiesSet方法会在初始化阶段被调用,我们先看看RequestMappingHandlerMapping的afterPropertiesSet方法会完成什么。(关于InitializingBean接口的afterPropertiesSet方法的调用时机在Bean的生命周期中很关键,可以参考:spring bean的生命周期初探 )
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
implements MatchableHandlerMapping, EmbeddedValueResolverAware {
//****省略****
@Override
public void afterPropertiesSet() {
//1.初始化配置
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
//2.调用AbstractHandlerMethodMapping中afterPropertiesSet的逻辑
super.afterPropertiesSet();
}
//****省略****
}
- 可以看到RequestMappingHandlerMapping在afterPropertiesSet回调方法中并未做太多操作,主要是做了一些配置的赋值,主要的事情父类 AbstractHandlerMethodMapping已经完成了,只需要super调用即可。
- AbstractHandlerMethodMapping#afterPropertiesSet:这是初始化的核心流程
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
- 主要逻辑在initHandlerMethods方法内部,代码如下:
- 小结一下initHandlerMethods流程就是获取全部的Bean,然后根据注解去判断是否需要处理,需要处理的就将类和方法的注解信息封装成对象保存到内部的MappingRegistry,MappingRegistry内部会有几个Map分类保存映射信息,最后有一个扩展的回调方法。
protected void initHandlerMethods() {
//1.获取容器中全部的Bean的名称
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
//2.根据名字获取类,判断该类是不是要转换的类型
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
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.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
//3.处理有Controller注解和RequestMapping注解的Bean
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
//4.所有映射方法都处理完成之后的回调方法,交给子类扩展,我貌似尚未找到实现方法,或许以后会扩展
handlerMethodsInitialized(getHandlerMethods());
}
//根据Controller和RequestMapping注解来决定Bean是否需要处理
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
- detectHandlerMethods: 遍历并且获取方法、信息封装合并并注册的主流程;(有些注解在类上,有些注解在方法上,需要合并)
protected void detectHandlerMethods(final Object handler) {
//1.根据Bean名称获取Bean,或者根据类型获取Bean
Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
//2.获取类对象
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//3.获取并且遍历类的所有方法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
//4.getMappingForMethod方法用于返回处理器的对应方法,这个逻辑是在RequestMappingHandlerMapping
//中实现的,在AbstractHandlerMethodMapping中没有实现
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
//5.注册扫描到的handler的方法
for (Map.Entry<Method, T> entry : methods.entrySet()) {
//Aop方法的处理
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
}
- registerHandlerMethod:将处理器方法注册到MappingRegistry属性内部的集合,
//注册扫描到的handler的方法,本质是保存在一个Map集合中
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
//注册请求和处理器映射关系
public void register(T mapping, Object handler, Method method) {
//1.加锁
this.readWriteLock.writeLock().lock();
try {
//2.新建HandlerMethod对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
//3.加入mappingLookup,请求对象对应的全部处理方法对象映射集合
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
//4.加入urlLookup,Url映射集合,获取请求路径,并将路径和处理器的映射关系保存到urlLookup
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
//5.加入nameLookup,
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
//5.加入corsLookup,跨域相关
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
//6.加入registry集合 RequestMappingInfo -> MappingRegistration的映射关系
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();//解锁
}
}
- getMappingForMethod: detectHandlerMethods中重写的用于从处理器类中获取到全部的处理方法,封装成一个RequestMappingInfo 对象返回,方法由RequestMappingHandlerMapping实现,定义在AbstractHandlerMethodMapping;
@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//信息合并
info = typeInfo.combine(info);
}
}
return info;
}
1.3 MappingRegistry
- AbstractHandlerMethodMapping.MappingRegistry是AbstractHandlerMethodMapping的一个内部类,用于保存映射关系,其内部通过几个Map保存了请求和处理器之间的映射关系;
private final MappingRegistry mappingRegistry = new MappingRegistry();
class MappingRegistry {
//RequestMappingInfo -> MappingRegistration的映射关系
private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
//RequestMappingInfo -> HandlerMethod的映射关系
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
//请求的Url -> RequestMappingInfo的映射关系,这里的T是一个LinkedHashMap,
//一个Url可能映射到多个RequestMappingInfo
//这些RequestMappingInfo就保存在一个LinkedHashMap里面
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
}
- 到这主体的初始化流程我们基本上摸清楚了,通过InitializingBean接口的afterPropertiesSet回调方法,扫描全部的Bean,得到处理器类和方法,封装好并通过映射关系保存在MappingRegistry属性的内部集合中,集合中包括多种映射关系。
- 不过还有一个疑问,RequestMappingHandlerMapping的afterPropertiesSet方法被回调,说明它自身也作为一个Bean在被初始化,入口是啥?没什么特别的,RequestMappingHandlerMapping也就是一个业务Bean,入口就是refresh -> finishBeanFactoryInitialization -> 进去根据Bean定义的BeanName初始化,本身没有什么特殊的。
1.4 RequestMappingHandlerMapping初始化入口
- RequestMappingHandlerMapping初始化和业务注册的Bean一样
AbstractApplicationContext#refresh
ConfigurableListableBeanFactory#preInstantiateSingletons
AbstractBeanFactory#getBean(java.lang.String)
AbstractBeanFactory#doGetBean
DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
二、获取Handler
- 由前面的内容我们知道了SpringMvc框架初始化RequestMappingHandlerMapping的过程,在初始化RequestMappingHandlerMapping的过程在,通过InitializingBean接口方法完成对Handler处理器方法的扫描并注册到内部的注册中心。后面我们来看看当框架收到有一个请求时候,如何找到对应的处理器方法。
2.1 HandlerMapping.getHandler
- getHandler方法定义在顶层接口HandlerMapping,通过HttpServletRequest参数,来获取该请求对应的处理器链对象HandlerExecutionChain,我们看看getHandler方法在AbstractHandlerMapping中的实现逻辑:
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//1.获取到处理request的HandlerMethod对象(参考2.2)
Object handler = getHandlerInternal(request);
//2.没有获取到就使用默认的
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
//3.如果获取到的是String类型的BeanName,就从容器获取对应的Bean实例
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
//4.获取执行链(获取执行链的细节和Spring监听器有关,可以后面再分析,即使自己没有写拦截器,默认也有框架内部的拦截器)
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//5.支持跨域的请求处理,默认不是的
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
//6.返回执行链
return executionChain;
}
2.2 getHandlerInternal
- getHandlerInternal方法根据request请求对象获取HandlerMethod对象,HandlerMethod封装了目标对象和目标方法等信息。
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//1.获取请求相对路径,比如"/hello"
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
//2.加读锁
this.mappingRegistry.acquireReadLock();
try {
//3.通过请求路径和请求对象寻找HandlerMethod处理对象
//HandlerMethod封装了目标方法等信息
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
//4.返回handlerMethod;createWithResolvedBean方法是将String类型的BeanName替换为从beanFactory获取的真正实例
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
- lookupHandlerMethod:根据Url和映射关系找到请求对应的处理方法对象HandlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
//1.从urlLookup获取url对应映射的RequestMappingInfo集合
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
//2.如果找到了,就把加到matches这个匹配集合
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
//3.如果集合为空,说明没找到,此时就扫描所有的映射集合
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
//4.找到最匹配的映射对象
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
- 到此我们对获取处理器的流程有了大概的眉目。通过HandlerMapping的getHandler方法获取HandlerExecutionChain处理器执行链,获取过程如下:
通过请求对象获取HandlerMethod处理器对象->
先根据Url获取,如果获取失败则会根据全部集合去寻找,
如果匹配对象一样会抛出异常
然后根据HandlerMethod获取执行链HandlerExecutionChain
- 下图是获取到处理器执行链之后的截图,内部包含处理器方法和拦截器链
三、拦截器初始化
- 拦截器初始化的初始化原本应该在第一步分析,因为从时机来说它在Handler初始化之前,我们前面看到过获取Handler处理器其实获取到的是一个执行链,内部封装了处理器Handler和一系列的拦截器,而且调试过程发现默认是有拦截器的,也可自定义,那么获取这些自定义的拦截器是在什么时候?我们慢慢分析。
3.1 定义拦截器
- 定义一个拦截器
@Component
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("preHandle...");
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ...");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("afterCompletion...");
}
}
- 注册前面的拦截器
@Component
public class RequestInterceptorRegister extends WebMvcConfigurerAdapter {
@Autowired
TestInterceptor testInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor).addPathPatterns("/**");
}
}
- 到此就可以实现一个自定义的拦截器来拦截所有的请求,不过具体拦截哪一些请求是可以配置的,前面的addPathPatterns("/**")是拦截全部的请求。
3.2 加载拦截器
- 回顾Bean的生命周期,在Bean的初始化之前会回调Aware系列接口(如果Bean实现了Aware系列接口,比如ApplicationContextAware),而我们的RequestMappingHandlerMapping继承了ApplicationObjectSupport,ApplicationObjectSupport是实现了ApplicationContextAware接口的,因此就会在这里回调ApplicationContextAware#setApplicationContext方法,在ApplicationObjectSupport父类中的setApplicationContext方法中实现了部分逻辑,并留下了Protected方法initApplicationContext给子类重写,而RequestMappingHandlerMapping正是通过这个重写的接口来完成拦截器的初始化的。(我们先看看下面的调用栈,然后分析源码)
3.2.1 AbstractHandlerMapping#initApplicationContext
- 先是invokeAwareInterfaces调用Aware系列接口,然后走到ApplicationObjectSupport的setApplicationContext,最终会回调AbstractHandlerMapping的initApplicationContext方法,代码如下:
//AbstractHandlerMapping#initApplicationContext
@Override
protected void initApplicationContext() throws BeansException {
//1.空方法,子类扩展,子类可以在这里添加拦截器
extendInterceptors(this.interceptors);
//2.侦测容器中的MappedInterceptor,并添加到adaptedInterceptors属性集合(一个List)
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
- 再看看是如何在容器中侦测拦截器的
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
- 下面是根据类型获取Bean的beansOfTypeIncludingAncestors方法,beansOfTypeIncludingAncestors方法会返回一个Map集合,因此前面通过values返回所有的拦截器Bean,这个方法内部代码不解析了,他的内部直接调用IOC容器根据类型去获取Bean对象,调试的时候发现,自己写的拦截器和框架内部的拦截器其实已经设置到interceptors属性了,也就是说initApplicationContext方法开始执行的时候,实际上拦截器早在此之前就扫描好了,由此推测拦截器的加载在此之前就加载好了,如下图所示:
BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), MappedInterceptor.class, true, false)
- 根据这点往回走,发现是在构造RequestMappingHandlerMapping这个Bean的时候设置的,代码如下:
//WebMvcConfigurationSupport#line280
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);//可以将断点打在这一行调试进入下面的getInterceptors方法
mapping.setInterceptors(getInterceptors()); //设置拦截器
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useSuffixPatternMatch != null) {
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
}
if (useRegisteredSuffixPatternMatch != null) {
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) {
mapping.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) {
mapping.setPathMatcher(pathMatcher);
}
return mapping;
}
- 而这里面设置拦截器的时候,通过getInterceptors() 方法获取拦截器,这比较关键:
//WebMvcConfigurationSupport#line329
protected final Object[] getInterceptors() {
//1.首次进来是null
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
//2.将DelegatingWebMvcConfiguration的configurers中保存的拦截器添加到registry对象
addInterceptors(registry);
//3.添加系统拦截器
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
this.interceptors = registry.getInterceptors();
}
//4.返回全部拦截器
return this.interceptors.toArray();
}
- 到此我们不需要往RequestMappingHandlerMapping的构造方法后面看了,我们知道了构造方法给RequestMappingHandlerMapping注入了全部的拦截器,但是拦截器是从DelegatingWebMvcConfiguration的configurers属性中得到的,那么configurers属性是什么时候赋值的?什么时候将全部的拦截器扫描然后保存到这个属性的?这就需要看后面的DelegatingWebMvcConfiguration的初始化过程了。
3.2.2 DelegatingWebMvcConfiguration
- 从前面一步一步我们都没有找到框架扫描拦截器的最早的地方,实际上是依靠DelegatingWebMvcConfiguration这个类来实现自定义拦截器的扫描和注册的,如下是关键代码。这个set注入方法将所有的WebMvcConfigurer组件都注册进去,而我们前面注册自定义的拦截器就是通过实现WebMvcConfigurerAdapter来注册的,(WebMvcConfigurerAdapter是WebMvcConfigurer的子类,因此我们的RequestInterceptorRegister也会在这里进行注入,并且会执行addWebMvcConfigurers方法将传入的拦截器对象添加到configurers属性)。
@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)) {
//1.遍历集合,将全部的连接器保存到configurers属性 (最终保存到了configurers对象的delegates属性)
this.configurers.addWebMvcConfigurers(configurers);
}
}
}
- WebMvcConfigurerComposite通过下面的addWebMvcConfigurers方法将所有的拦截器添加到delegates集合中去
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
}
- 进一步的问题是,这个setConfigurers方法是什么时候执行并扫描全部的拦截器组件的?而且我还有一个疑问就是,如果在实例化DelegatingWebMvcConfiguration这个Bean的过程中执行setConfigurers方法,此时我们的拦截器Bean尚未初始化好怎么办?这里并不是循环依赖,如果是循环依赖可以先创建需要依赖的Bean,带着这个疑问进一步看。
- 回头想想@Autowire的大概原理机制是怎么样的?可以参考:AutowiredAnnotationBeanPostProcessor
在WebMvcAutoConfiguration$EnableWebMvcConfiguration这个Bean的实例化过程中,在populateBean阶段会进入属性注入,(这里需要一些Bean生命周期的知识和对后置处理器的了解),在@Autowire字段注入的时候,依赖AutowiredAnnotationBeanPostProcessor处理器的处理,对setConfigurers方法进行处理。大概的调用栈我写出来了,并没有一一分析每一个方法。
//处理setConfigurers方法的调用栈,在populateBean阶段处理
AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject(line 622)
DefaultListableBeanFactory#resolveDependency(line 1047)
DefaultListableBeanFactory#doResolveDependency(line 1072)
DefaultListableBeanFactory#resolveMultipleBeans(line 1158)
DefaultListableBeanFactory#findAutowireCandidates(line 1273)
BeanFactoryUtils#beanNamesForTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<?>, boolean, boolean) (line 218)
DefaultListableBeanFactory#getBeanNamesForType(java.lang.Class<?>, boolean, boolean) (line 388)
DefaultListableBeanFactory#doGetBeanNamesForType (line405)
- 最后我们看看DefaultListableBeanFactory#findAutowireCandidates方法,该方法就是最终的@Autowire 方法注入的时候,根据BeanType去寻找目标Bean注入到指定BeanName的实例,参数如下:
beanName=WebMvcConfigurer
requiredType=WebMvcConfigurer(我们定义的拦截器就是这个类型的子类)
- 调试图如下:
- 到这我们基本知道了,DelegatingWebMvcConfiguration就是 通过@Autowire注入了全部的WebMvcConfigurer类型的Bean,我们自己写的拦截器也是在这一步注入的,不过后面的DefaultListableBeanFactory#doGetBeanNamesForType 方法,根据名字找Bean的类型,方法可以看看:
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();
// Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name
// is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
((mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading())) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// In case of FactoryBean, match object created by FactoryBean.
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
boolean matchFound =
(allowEagerInit || !isFactoryBean ||
(dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
(includeNonSingletons ||
(dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
isTypeMatch(beanName, type);
if (!matchFound && isFactoryBean) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException ex) {
//省略...
}
}
}
//省略....
return StringUtils.toStringArray(result);
}
- 从这里我们看到,他说从beanDefinitionNames中去寻找的,而不是直接去找已经创建好了的Bean,我想这应该是不必担心Bean创建顺序影响对拦截器扫描的原因吧。
- 下图可以看到,根据WebMvcConfigurer类型找到了两个Bean,其中一个是自定义的拦截器。
- 这一小节我们倒序梳理了拦截器的初始化大概的脉络。总结来说的话是通过DelegatingWebMvcConfiguration的初始化过程,通过@Autowire注解注入属性,其内部通过Bean的类型去到beanDefinitionNames中获取Bean名称,然后根据名称去IOC获取Bean实例。
四、小结
最后我们按照时序梳理一下:首先是扫描拦截器,流程如下:
在DelegatingWebMvcConfiguration的初始化过程,在其生命周期的属性注入阶段处理@Autowire的时候,通
过setConfigur方法,从beanDefinitionNames中创建并获取全部WebMvcConfigurer类型的Bean,然后保存在
其内部属性
- 然后是RequestMappingHandlerMapping的创建,构造方法部分
在RequestMappingHandlerMapping的创建过程中,其构造方法中会调用setInterceptors初始化内部的拦截器
属性,这一步是在WebMvcConfigurationSupport中创建的,他会将子类DelegatingWebMvcConfiguration中已经
初始化好的拦截器赋值给RequestMappingHandlerMapping
- 然后是RequestMappingHandlerMapping建立请求和处理器映射关系
RequestMappingHandlerMapping构造方法执行完毕之后,后面会经过Bean的生命周期中的InitializingBean接口回调,
借助该接口的afterPropertiesSet方法,在该方法中做初始化的过程,主要是在父类AbstractHandlerMethodMapping中
完成。他会从继承的ApplicationObjectSupport中获取到上下文容器applicationContext,从中获取到全部的Bean,然
后根据bean是否有Controller或者RequestMapping注解来决定是否需要处理这个Bean,对于我们写的Controller类肯定
是需要处理的,继而会获取上面的RequestMapping信息并封装成一个RequestMappingInfo对象,这里注意如果类型和方
法都添加了RequestMapping注解,会将两份信息都获取了并做合并。(RequestMapping注解既可以在类上也可以在方法上)。
然后将映射关系保存到Map集合,key是RequestMappingInfo对象或者Url,value是一个MappingRegistration对象,其内
部封装了RequestMappingInfo,处理方法(handlerMethod),Url(directUrls)等信息。
- 最后是Handler的获取
获取的时候,去RequestMappingHandlerMapping中获取处理器,首先会从请求对象中获取请求路径,根据Url去获取,
过程中会有一些完善机制,比如获取不到,异常等。获取到的是一个执行链,内部封装了目标方法和拦截器。
- 下面是我画的简图