initHandlerMappings()方法初始化有兩種方式:
1.setApplicationContext()
2.afterPropertiesSet()
1.setApplicationContext()實現方式如下:
首先進入DispatcherServlet 類中,可以看到DispatcherServlet 的繼承關係:
DispatcherServlet extends FrameworkServlet
FrameworkServlet extends HttpServletBean implements ApplicationContextAware
ApplicationContextAware中只有:
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
此方法setApplicationContext實現類在 ApplicationObjectSupport中:
ApplicationObjectSupport implements ApplicationContextAware
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
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(context);
protected void initApplicationContext(ApplicationContext context) throws BeansException {
initApplicationContext();
}
protected void initApplicationContext() throws BeansException {
}
initApplicationContext()方法由子類實現:
AbstractDetectingUrlHandlerMapping
SimpleUrlHandlerMapping
- AbstractDetectingUrlHandlerMapping實現:
public void initApplicationContext() throws ApplicationContextException {
//將匹配該映射器的Handler對象加入到this.HandlerMapping
super.initApplicationContext();
detectHandlers();
}
super.initApplicationContext();實現如下:
//super.initApplicationContext();實現在AbstractHandlerMapping類中:
//AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered
//攔截器一些設置
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
//探測ApplicationContext中已經解析過的MappedInterceptor
detectMappedInterceptors(this.adaptedInterceptors);
//初始化攔截器
initInterceptors();
}
//initInterceptors();
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
detectHandlers();實現如下:
protected void detectHandlers() throws BeansException {
ApplicationContext applicationContext = obtainApplicationContext();
if (logger.isDebugEnabled()) {
logger.debug("Looking for URL mappings in application context: " + applicationContext);
}
// 獲取ApplicationContext容器中所有bean的Name,並放入String數組中
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
// Take any bean name that we can determine URLs for.
// 遍歷beanNames,並找到這些bean對應的url
for (String beanName : beanNames) {
// 找bean上的所有url(controller上的url+方法上的url),該方法由對應的子類實現
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
// 保存urls和beanName的對應關係,put it to Map<urls,beanName>,該方法在父類AbstractUrlHandlerMapping中實現
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}
//AbstractDetectingUrlHandlerMapping類中detectHandlers方法中的 determineUrlsForHandler(beanName)方法:
/** 獲取controller中所有方法的url,由子類實現,典型的模板模式 **/
protected abstract String[] determineUrlsForHandler(String beanName);
----------------------------------------------------------------------------
//BeanNameUrlHandlerMapping 類中實現determineUrlsForHandler方法:
//檢查給定的bean名稱和別名,以“/”開頭匹配對應的urls轉換成數組並返回
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
----------------------------------------------------------------------------
AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping :
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
Assert.notNull(urlPaths, "URL path array must not be null");
for (String urlPath : urlPaths) {
registerHandler(urlPath, beanName);
}
}
AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered :
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;
// Eagerly resolve handler if referencing singleton via name.
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
if (urlPath.equals("/")) {
if (logger.isInfoEnabled()) {
logger.info("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isInfoEnabled()) {
logger.info("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isInfoEnabled()) {
logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}
2.SimpleUrlHandlerMapping 方法初始化:
SimpleUrlHandlerMapping 子類實現 initApplicationContext :
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}
super.initApplicationContext();實現類:
繼承自AbstractHandlerMapping:
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
繼承自AbstractHandlerMapping:
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
registerHandlers(this.urlMap);實現類:
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
urlMap.forEach((url, handler) -> {
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
});
}
}
AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping :
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;
// Eagerly resolve handler if referencing singleton via name.
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
if (urlPath.equals("/")) {
if (logger.isInfoEnabled()) {
logger.info("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isInfoEnabled()) {
logger.info("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isInfoEnabled()) {
logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}
從上面源碼可以看出 SimpleUrlHandlerMapping 映射器跟前面 BeanNameUrlHandlerMapping 映射器有點不一樣。
前者是先將加入該映射器的 handler 先加進該映射器的一個集合屬性裏面,容器初始化的時候免去了遍歷麻煩的步驟,後者是有點類似遍歷容器裏面有所的 bean 的 name 或 id 找到匹配的,並且 bean 的 name 或 id 有特殊要求,匹配的則加入。
AbstractHandlerMapping 實現類分支之二 AbstractHandlerMethodMapping
initHandlerMappings()初始化第二種方式:
AbstractHandlerMethodMapping類:
public void afterPropertiesSet() {
initHandlerMethods();
}
//處理controller中的各個方法的邏輯。首先得到所有的handler,對應開發者寫的controller;
//然後查找每個handler中映射請求的方法;最後初始化這些映射方法
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//獲取容器中註冊的所有的bean的name
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
//獲取對應bean的class
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);
}
}
// isHandler(beanType):具體什麼樣的bean滿足條件,實現類自己說了算
if (beanType != null && isHandler(beanType)) {
//對滿足的bean接着解析
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected abstract boolean isHandler(Class<?> beanType);
initHandlerMethods方法中的方法:
RequestMappingHandlerMapping 類中:
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
AbstractHandlerMethodMapping類:
protected void detectHandlerMethods(final Object handler) {
//獲取bean的class
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
//防止該bean是cglib生成的子類,獲取用戶自定義的bean的Class
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//得到該類的所有方法,遍歷並傳入閉包一個個進行判斷,合理的裝入Map,並返回
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
//該抽象類的抽象接口,實現類自定義該方法是否符合映射規則,並返回方法基本映射信息mapping對象
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
//將方法映射信息(Mapping),Beanname(Handler)以及方法對象(method)傳入register()方法
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
}
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
實現類在 RequestMappingHandlerMapping :
實現類在 RequestMappingHandlerMapping :
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//獲取Method上的RequestMappingInfo對象
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//獲取Class上的RequestMappingInfo對象
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//將Class上的映射信息和method上的映射信息做個整合
//例如@RequestMapping上的value,Class上的的拼上method的纔是完整的訪問路徑
info = typeInfo.combine(info);
}
}
return info;
}
//查看method或Class 上有沒有@RequestMapping註解,有的則創建返回記錄信息的RequestMappingInfo
@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
abstractHandlerMethodMapping類:
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
//檢測HandlerMethod和mapping映射關係是否唯一
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
this.mappingLookup.put(mapping, handlerMethod);
//因爲@RequestMapping裏面的value是一個數組,所以對應的路徑可能有多個
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);
}
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();
}
}
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
HandlerMethod handlerMethod;
if (handler instanceof String) {
String beanName = (String) handler;
handlerMethod = new HandlerMethod(beanName,
obtainApplicationContext().getAutowireCapableBeanFactory(), method);
}
else {
handlerMethod = new HandlerMethod(handler, method);
}
return handlerMethod;
}
以上就是initHandlerMappings()初始化的兩種方式。