SpringMvc學習心得(五)控制器產生與構建

    在springmvc中,控制器(controller)是一個很重要的概念。在實際項目中,我們一般在控制器裏完成具體的業務邏輯。控制器是非常重要,因此討論控制器的產生和構建就變得很有意義(PS:我們在這裏主要討論基於註解的配置方式)。

  在討論控制器的相關問題之前,需要考慮的第一個問題是:ApplicationContext的類型是如何確定的?ApplicationContext是spring的IOC機制實現的一個核心,spring的很多功能都是通過ApplicationContext對外輸出的。而springmvc的ApplicationContext則是“寫死”在FrameworkServlet這個類的field中。

  FrameworkServlet.java

public abstract class FrameworkServlet extends HttpServletBean {

	/**
	 * Suffix for WebApplicationContext namespaces. If a servlet of this class is
	 * given the name "test" in a context, the namespace used by the servlet will
	 * resolve to "test-servlet".
	 */
	public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";

	/**
	 * Default context class for FrameworkServlet.
	 * @see org.springframework.web.context.support.XmlWebApplicationContext
	 */
	public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
        //some other code
  而在XmlWebApplicationContext中,spring“手動”創建了一個ApplicationContextAwareProcessor,並將它註冊到beanfactory的beanPostProcessor列表中,具體代碼如下:

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
		Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
		this.beanPostProcessors.remove(beanPostProcessor);
		this.beanPostProcessors.add(beanPostProcessor);
		if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
			this.hasInstantiationAwareBeanPostProcessors = true;
		}
		if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
			this.hasDestructionAwareBeanPostProcessors = true;
		}
	}
  至此,產生和構建控制器的前置步驟就完成了。

   控制器的產生:打開@Controller這一註解的源代碼,你會發現該註解會被@Component這一註解所修飾。因此,所有被@Controller所修飾的類都會默認被@Component所修飾。同時這也意味着搭配<context:component-scan base-package="xxx.xxxx.xxxx" />這一標籤,所有被@Controller所修飾的類都會被註冊成爲JavaBean。這個JavaBean與其它自定義的JavaBean沒有什麼區別。而重要的區別則在於被@Controller所修飾的類,能夠被之前註冊的BeanPostProcessor所掃描並進行處理。

   控制器的構建:springmvc將構建控制器的這一工作交給了BeanPostProcessor進行處理。在<mvc:annotation-driven/>這一標籤裏,springmvc創建了一個JavaBean,這個bean是RequestMappingHandlerMapping。當這個JavaBean被反射出來但是還沒有被初始化的時候,BeanPostProcessor的postProcessBeforeInitialization會發揮作用。當然,由於會首先對JavaBean進行過濾。具體代碼如下:

if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
  RequestMappingHandlerMapping會使用Applicationcontext的getBeanNamesForType函數去查找所有基類是Object的JavaBean。顯而易見,所有的JavaBean都會通過該方法被掃描出來。然後對其中那些被@Controller所修飾的類進行進一步探測和處理。具體代碼如下:

 RequestMappingHandlerMapping掃描JavaBean並處理的方法:

protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}
		
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		for (String beanName : beanNames) {
			if (isHandler(getApplicationContext().getType(beanName))){
				detectHandlerMethods(beanName);
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}
   isHandler方法(ps:判斷是否爲控制器):

protected boolean isHandler(Class<?> beanType) {
		return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
	}

  RequestMappingHandlerMapping中一個很重要的函數是detectHandlerMethods。該函數具體代碼如下:

protected void detectHandlerMethods(final Object handler) {
		Class<?> handlerType = (handler instanceof String) ? 
				getApplicationContext().getType((String) handler) : handler.getClass();

		final Class<?> userType = ClassUtils.getUserClass(handlerType);
				
		Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
			public boolean matches(Method method) {
				return getMappingForMethod(method, userType) != null;
			}
		});
		
		for (Method method : methods) {
			T mapping = getMappingForMethod(method, userType);
			registerHandlerMethod(handler, method, mapping);
		}
	}
  可以看到,該函數主要工作是查找handler中的所有method,並根據method生成對應的mapping,並將mapping,method和handler進行註冊。而其中最重要的函數則是getMappingForMethod。該函數的主要邏輯是根據method產生一個RequestMappingInfo,然後根據handlerType產生另一個RequestMappingInfo。最後將這兩個RequestMappingInfo進行合併。該函數代碼如下:

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		RequestMappingInfo info = null;
		RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
		if (methodAnnotation != null) {
			RequestCondition<?> methodCondition = getCustomMethodCondition(method);
			info = createRequestMappingInfo(methodAnnotation, methodCondition);
			RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
			if (typeAnnotation != null) {
				RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
				info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
			}
		}
		return info;
	}
   RequestMappingHandlerMapping通過registerHandlerMethod函數對mapping,handler和method進行註冊,RequestMappingHandlerMapping會生成一個LinkedHashMap,並以mapping爲key,以handler和method爲value。 同時在註冊時會檢測mapping的是否重複。至此,controller的構建所示完成了。
  既然是以mapping爲可以,那麼必然會涉及equals函數和hashcode函數,下面是RequestMappingInfode 的equals函數以及hashcode函數。


public int hashCode() {
		int result = hash;
		if (result == 0) {
			result = patternsCondition.hashCode();
			result = 31 * result + methodsCondition.hashCode();
			result = 31 * result + paramsCondition.hashCode();
			result = 31 * result + headersCondition.hashCode();
			result = 31 * result + consumesCondition.hashCode();
			result = 31 * result + producesCondition.hashCode();
			result = 31 * result + customConditionHolder.hashCode();
			hash = result;
		}
		return result;
	}


public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj != null && obj instanceof RequestMappingInfo) {
			RequestMappingInfo other = (RequestMappingInfo) obj;
			return (this.patternsCondition.equals(other.patternsCondition) &&
					this.methodsCondition.equals(other.methodsCondition) &&
					this.paramsCondition.equals(other.paramsCondition) &&
					this.headersCondition.equals(other.headersCondition) &&
					this.consumesCondition.equals(other.consumesCondition) &&
					this.producesCondition.equals(other.producesCondition) && 
					this.customConditionHolder.equals(other.customConditionHolder));
		}
		return false;
	}

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