在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;
}