SpringMVC源碼解析一:HandlerMapping初始化

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 

 

  1. 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()初始化的兩種方式。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章