//ApplicationObjectSupport类@OverridepublicfinalvoidsetApplicationContext(@NullableApplicationContextcontext)throwsBeansException{if(context==null&&!isContextRequired()){// Reset internal context state.this.applicationContext=null;this.messageSourceAccessor=null;}elseif(this.applicationContext==null){// Initialize with passed-in context.if(!requiredContextClass().isInstance(context)){thrownewApplicationContextException("Invalid application context: needs to be of type ["+requiredContextClass().getName()+"]");}this.applicationContext=context;this.messageSourceAccessor=newMessageSourceAccessor(context);initApplicationContext(context);}else{// Ignore reinitialization if same context passed in.if(this.applicationContext!=context){thrownewApplicationContextException("Cannot reinitialize with different application context: current one is ["+this.applicationContext+"], passed-in one is ["+context+"]");}}}
/**
* Calls the {@link #detectHandlers()} method in addition to the
* superclass's initialization.
*/@OverridepublicvoidinitApplicationContext()throwsApplicationContextException{super.initApplicationContext();detectHandlers();}/** 建立当前ApplicationContext中的所有controller和url的对应关系
* Register all handlers found in the current ApplicationContext.
* <p>The actual URL determination for a handler is up to the concrete
* {@link #determineUrlsForHandler(String)} implementation. A bean for
* which no such URLs could be determined is simply not considered a handler.
* @throws org.springframework.beans.BeansException if the handler couldn't be registered
* @see #determineUrlsForHandler(String)
*/protectedvoiddetectHandlers()throwsBeansException{ApplicationContextapplicationContext=obtainApplicationContext();String[]beanNames=(this.detectHandlersInAncestorContexts?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext,Object.class):applicationContext.getBeanNamesForType(Object.class));// 获取ApplicationContext容器中所有bean的Name// Take any bean name that we can determine URLs for.// 遍历beanNames,并找到这些bean对应的urlfor(StringbeanName: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);}}if((logger.isDebugEnabled()&&!getHandlerMap().isEmpty())||logger.isTraceEnabled()){logger.debug("Detected "+getHandlerMap().size()+" mappings in "+formatMappingName());}}/**
* Determine the URLs for the given handler bean.
* @param beanName the name of the candidate bean
* @return the URLs determined for the bean, or an empty array if none
*//** 获取controller中所有方法的url,由子类实现,典型的模板模式 **/protectedabstractString[]determineUrlsForHandler(StringbeanName);
publicclassBeanNameUrlHandlerMappingextendsAbstractDetectingUrlHandlerMapping{/**
* Checks name and aliases of the given bean for URLs, starting with "/".
* 找出名字或者别名是以 / 开头的bean
*/@OverrideprotectedString[]determineUrlsForHandler(StringbeanName){List<String>urls=newArrayList<>();if(beanName.startsWith("/")){urls.add(beanName);}String[]aliases=obtainApplicationContext().getAliases(beanName);for(Stringalias:aliases){if(alias.startsWith("/")){urls.add(alias);}}returnStringUtils.toStringArray(urls);}}
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*//** 中央控制器,控制请求的转发 **/protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{HttpServletRequestprocessedRequest=request;HandlerExecutionChainmappedHandler=null;booleanmultipartRequestParsed=false;WebAsyncManagerasyncManager=WebAsyncUtils.getAsyncManager(request);try{ModelAndViewmv=null;ExceptiondispatchException=null;try{// 1.检查是否是文件上传的请求processedRequest=checkMultipart(request);multipartRequestParsed=(processedRequest!=request);// Determine handler for the current request.// 2.取得处理当前请求的controller,这里也称为hanlder,处理器// 第一个步骤的意义就在这里体现了.这里并不是直接返回controller,// 而是返回的HandlerExecutionChain请求处理器链对象,// 该对象封装了handler和interceptors.mappedHandler=getHandler(processedRequest);if(mappedHandler==null){noHandlerFound(processedRequest,response);return;}// Determine handler adapter for the current request.//3. 获取处理request的处理器适配器handler adapter HandlerAdapterha=getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.// 处理 last-modified 请求头Stringmethod=request.getMethod();booleanisGet="GET".equals(method);if(isGet||"HEAD".equals(method)){longlastModified=ha.getLastModified(request,mappedHandler.getHandler());if(newServletWebRequest(request,response).checkNotModified(lastModified)&&isGet){return;}}// 4.拦截器的预处理方法if(!mappedHandler.applyPreHandle(processedRequest,response)){return;}// Actually invoke the handler.// 5.实际的处理器处理请求,返回结果视图对象mv=ha.handle(processedRequest,response,mappedHandler.getHandler());if(asyncManager.isConcurrentHandlingStarted()){return;}// 结果视图对象的处理applyDefaultViewName(processedRequest,mv);// 6.拦截器的后处理方法mappedHandler.applyPostHandle(processedRequest,response,mv);}catch(Exceptionex){dispatchException=ex;}catch(Throwableerr){// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException=newNestedServletException("Handler dispatch failed",err);}//将结果解析为ModelAndViewprocessDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException);}catch(Exceptionex){// 请求成功响应之后的方法triggerAfterCompletion(processedRequest,response,mappedHandler,ex);}catch(Throwableerr){triggerAfterCompletion(processedRequest,response,mappedHandler,newNestedServletException("Handler processing failed",err));}finally{if(asyncManager.isConcurrentHandlingStarted()){// Instead of postHandle and afterCompletionif(mappedHandler!=null){mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest,response);}}else{// Clean up any resources used by a multipart request.if(multipartRequestParsed){cleanupMultipart(processedRequest);}}}}
/**
* Invoke the method and handle the return value through one of the
* configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}.
* @param webRequest the current request
* @param mavContainer the ModelAndViewContainer for this request
* @param providedArgs "given" arguments matched by type (not resolved)
*/publicvoidinvokeAndHandle(ServletWebRequestwebRequest,ModelAndViewContainermavContainer,Object...providedArgs)throwsException{//执行请求对应的方法,并获得返回值ObjectreturnValue=invokeForRequest(webRequest,mavContainer,providedArgs);setResponseStatus(webRequest);if(returnValue==null){if(isRequestNotModified(webRequest)||getResponseStatus()!=null||mavContainer.isRequestHandled()){mavContainer.setRequestHandled(true);return;}}elseif(StringUtils.hasText(getResponseStatusReason())){mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);Assert.state(this.returnValueHandlers!=null,"No return value handlers");try{this.returnValueHandlers.handleReturnValue(returnValue,getReturnValueType(returnValue),mavContainer,webRequest);}catch(Exceptionex){if(logger.isTraceEnabled()){logger.trace(formatErrorForReturnValue(returnValue),ex);}throwex;}}
//InvocableHandlerMethod类 /**
* Invoke the handler method with the given argument values.
*/@NullableprotectedObjectdoInvoke(Object...args)throwsException{//反射之前 取消Java的权限控制检查ReflectionUtils.makeAccessible(getBridgedMethod());try{//通过执行controller中的方法returngetBridgedMethod().invoke(getBean(),args);}catch(IllegalArgumentExceptionex){assertTargetBean(getBridgedMethod(),getBean(),args);Stringtext=(ex.getMessage()!=null?ex.getMessage():"Illegal argument");thrownewIllegalStateException(formatInvokeError(text,args),ex);}catch(InvocationTargetExceptionex){// Unwrap for HandlerExceptionResolvers ...ThrowabletargetException=ex.getTargetException();if(targetExceptioninstanceofRuntimeException){throw(RuntimeException)targetException;}elseif(targetExceptioninstanceofError){throw(Error)targetException;}elseif(targetExceptioninstanceofException){throw(Exception)targetException;}else{thrownewIllegalStateException(formatInvokeError("Invocation failure",args),targetException);}}}
privateObject[]resolveHandlerArguments(MethodhandlerMethod,Objecthandler,NativeWebRequestwebRequest,ExtendedModelMapimplicitModel)throwsException{// 1.获取方法参数类型的数组Class[]paramTypes=handlerMethod.getParameterTypes();// 声明数组,存参数的值Object[]args=newObject[paramTypes.length];//2.遍历参数数组,获取每个参数的值for(inti=0;i<args.length;i++){MethodParametermethodParam=newMethodParameter(handlerMethod,i);methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);GenericTypeResolver.resolveParameterType(methodParam,handler.getClass());StringparamName=null;StringheaderName=null;booleanrequestBodyFound=false;StringcookieName=null;StringpathVarName=null;StringattrName=null;booleanrequired=false;StringdefaultValue=null;booleanvalidate=false;intannotationsFound=0;Annotation[]paramAnns=methodParam.getParameterAnnotations();// 处理参数上的注解for(AnnotationparamAnn:paramAnns){if(RequestParam.class.isInstance(paramAnn)){RequestParamrequestParam=(RequestParam)paramAnn;paramName=requestParam.value();required=requestParam.required();defaultValue=parseDefaultValueAttribute(requestParam.defaultValue());annotationsFound++;}elseif(RequestHeader.class.isInstance(paramAnn)){RequestHeaderrequestHeader=(RequestHeader)paramAnn;headerName=requestHeader.value();required=requestHeader.required();defaultValue=parseDefaultValueAttribute(requestHeader.defaultValue());annotationsFound++;}elseif(RequestBody.class.isInstance(paramAnn)){requestBodyFound=true;annotationsFound++;}elseif(CookieValue.class.isInstance(paramAnn)){CookieValuecookieValue=(CookieValue)paramAnn;cookieName=cookieValue.value();required=cookieValue.required();defaultValue=parseDefaultValueAttribute(cookieValue.defaultValue());annotationsFound++;}elseif(PathVariable.class.isInstance(paramAnn)){PathVariablepathVar=(PathVariable)paramAnn;pathVarName=pathVar.value();annotationsFound++;}elseif(ModelAttribute.class.isInstance(paramAnn)){ModelAttributeattr=(ModelAttribute)paramAnn;attrName=attr.value();annotationsFound++;}elseif(Value.class.isInstance(paramAnn)){defaultValue=((Value)paramAnn).value();}elseif("Valid".equals(paramAnn.annotationType().getSimpleName())){validate=true;}}if(annotationsFound>1){thrownewIllegalStateException("Handler parameter annotations are exclusive choices - "+"do not specify more than one such annotation on the same parameter: "+handlerMethod);}if(annotationsFound==0){// 如果没有注解ObjectargValue=resolveCommonArgument(methodParam,webRequest);if(argValue!=WebArgumentResolver.UNRESOLVED){args[i]=argValue;}elseif(defaultValue!=null){args[i]=resolveDefaultValue(defaultValue);}else{ClassparamType=methodParam.getParameterType();// 将方法声明中的Map和Model参数,放到request中,用于将数据放到request中带回页面if(Model.class.isAssignableFrom(paramType)||Map.class.isAssignableFrom(paramType)){args[i]=implicitModel;}elseif(SessionStatus.class.isAssignableFrom(paramType)){args[i]=this.sessionStatus;}elseif(HttpEntity.class.isAssignableFrom(paramType)){args[i]=resolveHttpEntityRequest(methodParam,webRequest);}elseif(Errors.class.isAssignableFrom(paramType)){thrownewIllegalStateException("Errors/BindingResult argument declared "+"without preceding model attribute. Check your handler method signature!");}elseif(BeanUtils.isSimpleProperty(paramType)){paramName="";}else{attrName="";}}}// 从request中取值,并进行赋值操作if(paramName!=null){// 根据paramName从request中取值,如果没有通过RequestParam注解指定paramName,则使用asm读取class文件来获取paramNameargs[i]=resolveRequestParam(paramName,required,defaultValue,methodParam,webRequest,handler);}elseif(headerName!=null){args[i]=resolveRequestHeader(headerName,required,defaultValue,methodParam,webRequest,handler);}elseif(requestBodyFound){args[i]=resolveRequestBody(methodParam,webRequest,handler);}elseif(cookieName!=null){args[i]=resolveCookieValue(cookieName,required,defaultValue,methodParam,webRequest,handler);}elseif(pathVarName!=null){args[i]=resolvePathVariable(pathVarName,methodParam,webRequest,handler);}elseif(attrName!=null){WebDataBinderbinder=resolveModelAttribute(attrName,methodParam,implicitModel,webRequest,handler);booleanassignBindingResult=(args.length>i+1&&Errors.class.isAssignableFrom(paramTypes[i+1]));if(binder.getTarget()!=null){doBind(binder,webRequest,validate,!assignBindingResult);}args[i]=binder.getTarget();if(assignBindingResult){args[i+1]=binder.getBindingResult();i++;}implicitModel.putAll(binder.getBindingResult().getModel());}}// 返回参数值数组returnargs;}
volatileObjectsecurityCheckCache;voidcheckAccess(Class<?>caller,Class<?>clazz,Objectobj,intmodifiers)throwsIllegalAccessException{if(caller==clazz){// 快速校验return;// 权限通过校验}Objectcache=securityCheckCache;// read volatileClass<?>targetClass=clazz;if(obj!=null&&Modifier.isProtected(modifiers)&&((targetClass=obj.getClass())!=clazz)){// Must match a 2-list of { caller, targetClass }.if(cacheinstanceofClass[]){Class<?>[]cache2=(Class<?>[])cache;if(cache2[1]==targetClass&&cache2[0]==caller){return;// ACCESS IS OK}// (Test cache[1] first since range check for [1]// subsumes range check for [0].)}}elseif(cache==caller){// Non-protected case (or obj.class == this.clazz).return;// ACCESS IS OK}// If no return, fall through to the slow path.slowCheckMemberAccess(caller,clazz,obj,modifiers,targetClass);}
// Keep all this slow stuff out of line:voidslowCheckMemberAccess(Class<?>caller,Class<?>clazz,Objectobj,intmodifiers,Class<?>targetClass)throwsIllegalAccessException{Reflection.ensureMemberAccess(caller,clazz,obj,modifiers);// Success: Update the cache.Objectcache=((targetClass==clazz)?caller:newClass<?>[]{caller,targetClass});// Note: The two cache elements are not volatile,// but they are effectively final. The Java memory model// guarantees that the initializing stores for the cache// elements will occur before the volatile write.securityCheckCache=cache;// write volatile}
privatevolatileMethodAccessormethodAccessor;// For sharing of MethodAccessors. This branching structure is// currently only two levels deep (i.e., one root Method and// potentially many Method objects pointing to it.)//// If this branching structure would ever contain cycles, deadlocks can// occur in annotation code.privateMethodroot;
那么MethodAccessor到底是个啥玩意呢?
1
2
3
4
5
6
7
8
9
10
/** This interface provides the declaration for
java.lang.reflect.Method.invoke(). Each Method object is
configured with a (possibly dynamically-generated) class which
implements this interface.
*/publicinterfaceMethodAccessor{/** Matches specification in {@link java.lang.reflect.Method} */publicObjectinvoke(Objectobj,Object[]args)throwsIllegalArgumentException,InvocationTargetException;}
// NOTE that there is no synchronization used here. It is correct// (though not efficient) to generate more than one MethodAccessor// for a given Method. However, avoiding synchronization will// probably make the implementation more scalable.privateMethodAccessoracquireMethodAccessor(){// First check to see if one has been created yet, and take it// if soMethodAccessortmp=null;if(root!=null)tmp=root.getMethodAccessor();if(tmp!=null){methodAccessor=tmp;}else{// Otherwise fabricate one and propagate it up to the roottmp=reflectionFactory.newMethodAccessor(this);setMethodAccessor(tmp);}returntmp;}
// Reflection factory used by subclasses for creating field,// method, and constructor accessors. Note that this is called// very early in the bootstrapping process.staticfinalReflectionFactoryreflectionFactory=AccessController.doPrivileged(newsun.reflect.ReflectionFactory.GetReflectionFactoryAction());
publicclassReflectionFactory{privatestaticbooleaninitted=false;privatestaticPermissionreflectionFactoryAccessPerm=newRuntimePermission("reflectionFactoryAccess");privatestaticReflectionFactorysoleInstance=newReflectionFactory();// Provides access to package-private mechanisms in java.lang.reflectprivatestaticvolatileLangReflectAccesslangReflectAccess;// 这里设计得非常巧妙// "Inflation" mechanism. Loading bytecodes to implement// Method.invoke() and Constructor.newInstance() currently costs// 3-4x more than an invocation via native code for the first// invocation (though subsequent invocations have been benchmarked// to be over 20x faster). Unfortunately this cost increases// startup time for certain applications that use reflection// intensively (but only once per class) to bootstrap themselves.// To avoid this penalty we reuse the existing JVM entry points// for the first few invocations of Methods and Constructors and// then switch to the bytecode-based implementations.//// Package-private to be accessible to NativeMethodAccessorImpl// and NativeConstructorAccessorImplprivatestaticbooleannoInflation=false;privatestaticintinflationThreshold=15;//......//这是生成MethodAccessor的方法publicMethodAccessornewMethodAccessor(Methodmethod){checkInitted();if(noInflation&&!ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())){returnnewMethodAccessorGenerator().generateMethod(method.getDeclaringClass(),method.getName(),method.getParameterTypes(),method.getReturnType(),method.getExceptionTypes(),method.getModifiers());}else{NativeMethodAccessorImplacc=newNativeMethodAccessorImpl(method);DelegatingMethodAccessorImplres=newDelegatingMethodAccessorImpl(acc);acc.setParent(res);returnres;}}//....../** We have to defer full initialization of this class until after
the static initializer is run since java.lang.reflect.Method's
static initializer (more properly, that for
java.lang.reflect.AccessibleObject) causes this class's to be
run, before the system properties are set up. */privatestaticvoidcheckInitted(){if(initted)return;AccessController.doPrivileged(newPrivilegedAction<Void>(){publicVoidrun(){// Tests to ensure the system properties table is fully// initialized. This is needed because reflection code is// called very early in the initialization process (before// command-line arguments have been parsed and therefore// these user-settable properties installed.) We assume that// if System.out is non-null then the System class has been// fully initialized and that the bulk of the startup code// has been run.if(System.out==null){// java.lang.System not yet fully initializedreturnnull;}Stringval=System.getProperty("sun.reflect.noInflation");if(val!=null&&val.equals("true")){noInflation=true;}val=System.getProperty("sun.reflect.inflationThreshold");if(val!=null){try{inflationThreshold=Integer.parseInt(val);}catch(NumberFormatExceptione){thrownewRuntimeException("Unable to parse property sun.reflect.inflationThreshold",e);}}initted=true;returnnull;}});}}
/** Delegates its invocation to another MethodAccessorImpl and can
change its delegate at run time. */classDelegatingMethodAccessorImplextendsMethodAccessorImpl{privateMethodAccessorImpldelegate;DelegatingMethodAccessorImpl(MethodAccessorImpldelegate){setDelegate(delegate);}publicObjectinvoke(Objectobj,Object[]args)throwsIllegalArgumentException,InvocationTargetException{returndelegate.invoke(obj,args);}voidsetDelegate(MethodAccessorImpldelegate){this.delegate=delegate;}}
/** Used only for the first few invocations of a Method; afterward,
switches to bytecode-based implementation */classNativeMethodAccessorImplextendsMethodAccessorImpl{privateMethodmethod;privateDelegatingMethodAccessorImplparent;privateintnumInvocations;NativeMethodAccessorImpl(Methodmethod){this.method=method;}publicObjectinvoke(Objectobj,Object[]args)throwsIllegalArgumentException,InvocationTargetException{// We can't inflate methods belonging to vm-anonymous classes because// that kind of class can't be referred to by name, hence can't be// found from the generated bytecode.if(++numInvocations>ReflectionFactory.inflationThreshold()&&!ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())){MethodAccessorImplacc=(MethodAccessorImpl)newMethodAccessorGenerator().generateMethod(method.getDeclaringClass(),method.getName(),method.getParameterTypes(),method.getReturnType(),method.getExceptionTypes(),method.getModifiers());parent.setDelegate(acc);}returninvoke0(method,obj,args);}voidsetParent(DelegatingMethodAccessorImplparent){this.parent=parent;}privatestaticnativeObjectinvoke0(Methodm,Objectobj,Object[]args);}
JVM_ENTRY(jobject,JVM_InvokeMethod(JNIEnv*env,jobjectmethod,jobjectobj,jobjectArrayargs0))JVMWrapper("JVM_InvokeMethod");Handlemethod_handle;if(thread->stack_available((address)&method_handle)>=JVMInvokeMethodSlack){method_handle=Handle(THREAD,JNIHandles::resolve(method));Handlereceiver(THREAD,JNIHandles::resolve(obj));objArrayHandleargs(THREAD,objArrayOop(JNIHandles::resolve(args0)));oopresult=Reflection::invoke_method(method_handle(),receiver,args,CHECK_NULL);jobjectres=JNIHandles::make_local(env,result);if(JvmtiExport::should_post_vm_object_alloc()){oopret_type=java_lang_reflect_Method::return_type(method_handle());assert(ret_type!=NULL,"sanity check: ret_type oop must not be NULL!");if(java_lang_Class::is_primitive(ret_type)){// Only for primitive type vm allocates memory for java object.
// See box() method.
JvmtiExport::post_vm_object_alloc(JavaThread::current(),result);}}returnres;}else{THROW_0(vmSymbols::java_lang_StackOverflowError());}JVM_END
/** Generator for sun.reflect.MethodAccessor and
sun.reflect.ConstructorAccessor objects using bytecodes to
implement reflection. A java.lang.reflect.Method or
java.lang.reflect.Constructor object can delegate its invoke or
newInstance method to an accessor using native code or to one
generated by this class. (Methods and Constructors were merged
together in this class to ensure maximum code sharing.) */