文章目录
前言
接着 springmvc-源码调试-3.0本文主要分析一个方法…initHandlerMappings
springMVC 重中之重
HadnlerMappings 处理器映射器
需要说明的是 !! HandlerMapping 实现各有不同… 而我直接采用的 spring 源码 运行起来的,也就是说大部分为默认…
initHandlerMappings
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 该值默认为 true 但是可以设置为 false
// 如果设置为 false 那 Spring MVC就只会查找名为“handlerMapping”的bean,并作为当前系统的唯一的HandlerMapping
// 如果是 ture 则查询所有的..
if (this.detectAllHandlerMappings) {
//在ApplicationContext中查找所有handler映射,包括父类上下文。
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
//如果不为空
if (!matchingBeans.isEmpty()) {
// 将获取的 HandlerMapping 转换成集合..
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// 排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
// 从容器中获取 HandlerMapping ,如果获取不到 下面则会添加默认的..
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
//稍后就会创建一个默认的~~~
}
}
//通过注册,确保至少有一个HandlerMapping
//如果找不到其他映射,则为默认的HandlerMapping。
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
for (HandlerMapping mapping : this.handlerMappings) {
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}
getDefaultStrategies
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
if (defaultStrategies == null) {
try {
// 从配置文件加载默认的 简单的说 加载 DispatcherServlet.properties 这个文件...
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
// 默认的策略~~~
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
//获取 org.springframework.web.servlet.HandlerMapping
String key = strategyInterface.getName();
// org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
// org.springframework.web.servlet.function.support.RouterFunctionMapping
String value = defaultStrategies.getProperty(key);
if (value != null) {
// 将 获取的 value 转换成数组
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
// 循环
for (String className : classNames) {
try {
// 根据 路径获取 class
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
// 创建...
Object strategy = createDefaultStrategy(context, clazz);
// 添加到集合中
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
// 抛出异常
}
catch (LinkageError err) {
// 抛出异常
}
}
return strategies;
}
else {
return new LinkedList<>();
}
}
上面没什么可说的… 只要就是 createDefaultStrategy()
会循环三次… 也就说会默认创建 HandlerMapping
- BeanNameUrlHandlerMapping
- RequestMappingHandlerMapping
- RouterFunctionMapping
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}
public <T> T createBean(Class<T> beanClass) throws BeansException {
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);
bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
// 创建Bean..
return (T) createBean(beanClass.getName(), bd, null);
}
上面的源码不过多深究了。。就是创建Bean去了
BeanNameUrlHandlerMapping
先看一下该类的接口关系…因为关系到了一些方法的初始化回调… 如果你不看你压根就不知道这个方法在啥时候执行的…
可以看到 该类还是 一个 aware 类型. 而 spring 中 通过 这些回调帮助我们设置一些内容… 也就是说 spring 会回调这三个接口中的方法…
所以还得需要知道这三个接口定义了什么…
ApplicationContextAware:会帮我们注入 ApplicationContext
ServletContextAware: 会帮我们注 入ServletContext
BeanNameAware : 会帮我们注入 这个BeanName
那也就意味着 整个关系链中有 这三个接口的实现,从上图关系链中
AbstractHandlerMappin
实现了 BeanNameAware
看了下源码里面并没有其他的动作… 所以不必深究,主要看一下 setApplicationContext
setApplicationContext
ApplicationObjectSupport
实现了 ApplicationContextAware
也就说在创建对象的时候会调用setApplicationContext(ApplicationContext context)
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
// 由于是回调方法.. 所以 context 不可能是为null,条件不成立进入else
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// 如果传入了相同的上下文,则忽略重新初始化。
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
// 主要是这里....
initApplicationContext(context);
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is [" +
this.applicationContext + "], passed-in one is [" + context + "]");
}
}
}
initApplicationContext
如果单纯的IDEA 点方法会发现最后是一个空方法… 这个是由子类去覆盖的而我们的子类是一大坨…所以还是根据IDEA 堆栈 去看。。
可以看到 WebApplicationObjectSupport 重写了 ApplicationObjectSupport.initApplicationContext()
方法…
protected void initApplicationContext(ApplicationContext context) {
// 这里有去调用父类的.. initApplicationContext(ApplicationContext context)
// 也就是调用 ApplicationObjectSupport.initApplicationContext()
super.initApplicationContext(context);
// 如果 servletContext 为空 并且 servletContext 是 WebApplicationContext类型
if (this.servletContext == null && context instanceof WebApplicationContext) {
// 强制获取 ServletContext
this.servletContext = ((WebApplicationContext) context).getServletContext();
// 如果 不是空的 则会去初始化..
if (this.servletContext != null) {
// 这里先不分析..
initServletContext(this.servletContext);
}
}
}
ApplicationObjectSupport.initApplicationContext()
这个方法是有子类调用的… 因为 子类调用的时候加了upser.initApplicationContext()
protected void initApplicationContext(ApplicationContext context) throws BeansException {
// 继续调用.. 由于当前类是 BeanNameUrlHandlerMapping ,
// 所以会调用 BeanNameUrlHandlerMapping里面的 initApplicationContext 如果没有则会调用父类.. 如果父类没有则会调用父类的父类.
// 如果都没有 则会调用 空实现..
// 而这里则有 AbstractDetectingUrlHandlerMapping 去重写了..所以调用的是 AbstractDetectingUrlHandlerMapping
initApplicationContext();
}
AbstractDetectingUrlHandlerMapping.initApplicationContext()
public void initApplicationContext() throws ApplicationContextException {
//这里由去调用父类..走到这里我人傻了......
super.initApplicationContext();
detectHandlers();
}
initApplicationContext()
AbstractHandlerMapping.initApplicationContext()
protected void initApplicationContext() throws BeansException {
// 里面是一个空实现..
extendInterceptors(this.interceptors);
// 获取所有的 MappedInterceptor 并且放入到 List(adaptedInterceptors)集合
// 简单来说就是根据 MappedInterceptor 获取其所有的 子类.
detectMappedInterceptors(this.adaptedInterceptors);
// 初始化拦截器..
initInterceptors();
}
detectHandlers()
protected void detectHandlers() throws BeansException {
// 获取 ApplicationContext
ApplicationContext applicationContext = obtainApplicationContext();
// 获取容器中所有的 beanName
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
registerHandler(urls, beanName);
}
}
if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
}
}
多态搞死人,大致调用链…
在看一下继承链主要怕你们绕晕…
RequestMappingHandlerMapping
主要分析 InitializingBean,如果对该接口不太熟悉的… 可以去了解一下.这里简单说一下
简单说实现 InitializingBean 接口 里面有一个方法,其作用就是在初始化的时候做一个回调,比如
@PostConstruct
这个注解总知道吧…同理…
这里不分析 ApplicationContextAware,是因为跟 BeanNameUrlHandlerMapping 没啥区别… 没做什么特别的事情…
afterPropertiesSet()
RequestMappingHandlerMapping.afterPropertiesSet();
public void afterPropertiesSet() {
// 创建 BuilderConfiguration
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setTrailingSlashMatch(useTrailingSlashMatch());
this.config.setContentNegotiationManager(getContentNegotiationManager());
if (getPatternParser() != null) {
this.config.setPatternParser(getPatternParser());
Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
"Suffix pattern matching not supported with PathPatternParser.");
}
else {
this.config.setSuffixPatternMatch(useSuffixPatternMatch());
this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
this.config.setPathMatcher(getPathMatcher());
}
super.afterPropertiesSet();
}
afterPropertiesSet();
AbstractHandlerMethodMapping.afterPropertiesSet()
public void afterPropertiesSet() {
initHandlerMethods();
}
initHandlerMethods()
初始化 HandlerMethods
protected void initHandlerMethods() {
// 获取所有的 BeanNames
for (String beanName : getCandidateBeanNames()) {
// 判断不是已 scopedTarget 开头
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);
}
catch (Throwable ex) {
// 一个无法解析的bean类型,可能来自一个lazy bean-让我们忽略它。
// 日志打印...
}
// 不是null 并且 类型是存在 @Controller 或者 @RequestMapping 注解
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
isHandler
protected boolean isHandler(Class<?> beanType) {
// 存在 Controller注解 或者存在 RequestMapping 注解 ..
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
detectHandlerMethods
protected void detectHandlerMethods(Object handler) {
// 如果传递是 String 则 获取其类型 ,如果是是class 则直接返回
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
// 获取用户 class 而非 代理类 或者Object.class
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 传递 Class 对这个 Class 所有方法进行校验..
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// 里面主要是 获取 方法 和类上的 @RequestMapping 将其合并.
// 如果没有的话则会返回 null,而由于是 lambda 这里主要是制订过滤规则
// 如果返回了 null 则 selectMethods 不会将其放入到Map中。
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
//循环所有
methods.forEach((method, mapping) -> {
//再次核查方法与类型是否匹配
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 如果是满足要求的方法,则注册到全局的MappingRegistry实例里
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
以上所有的代码就是去处理 @RequestMapping
RouterFunctionMapping
跟 RequestMappingHandlerMapping
的继承体系差不多…这里就不贴图了…
主要分析 InitializingBean,如果对该接口不太熟悉的… 可以去了解一下.这里简单说一下
简单说实现 InitializingBean 接口 里面有一个方法,其作用就是在初始化的时候做一个回调,比如
@PostConstruct
这个注解总知道吧…同理…
afterPropertiesSet
public void afterPropertiesSet() throws Exception {
if (this.routerFunction == null) {
// 这里不深究了 .. 这里是处理 RouterFunction
initRouterFunction();
}
// 如果 消息转换器 为空的 话初始化
if (CollectionUtils.isEmpty(this.messageConverters)) {
initMessageConverters();
}
}
initMessageConverters
主要添加了4个转换器…
private void initMessageConverters() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(4);
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
if (!shouldIgnoreXml) {
try {
messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
this.messageConverters = messageConverters;
}
后言
这里简单将一下 几个回调…
首先ApplicationContextAware 就是你实现这个借口会有一个回调… 如何做的呢?
- spring 去创建这个Bean的时候,注册了ApplicationContextAwareProcessor
- 在每一个对象创建的时候 都会走 ApplicationContextAwareProcessor .postProcessBeforeInitialization 方法
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 看到了吧 这里 判断你是不是 这个类型的...
// 而我们的上面三个类都是实现了 ApplicationContextAware 接口..
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
// 这里是去进行回调去了..
invokeAwareInterfaces(bean);
}
return bean;
}
invokeAwareInterfaces:一顿瞎几把判断… 然后转换执行即可…
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
后后言
如有问题欢迎指导交流