今天主要聊聊Controller、Service和Component这三个注解的关系和区别。网上很多人对这三个注解进行了详细的解释,但是仅仅局限于理论,个人对于没有经过自己验证的结果总是持怀疑态度,所有花时间研究了一下,也对这三个注解理解的更加透彻。(ps:网上好多回答不一定正确,所以只能自己花时间验证) 附上三个注解的源代码:Target(ElementType。TYPE)Retention(RetentionPolicy。RUNTIME)DocumentedIndexedpublicinterfaceComponent{Stringvalue()}Target({ElementType。TYPE})Retention(RetentionPolicy。RUNTIME)DocumentedComponent关键注解publicinterfaceController{AliasFor(annotationComponent。class)Stringvalue()}Target({ElementType。TYPE})Retention(RetentionPolicy。RUNTIME)DocumentedComponent关键注解publicinterfaceService{AliasFor(annotationComponent。class)Stringvalue()}注解扫描 首先说说这三个注解的关系,从源码中可以看出,Controller和Service都派生于Component,所以三者的使用方式基本没什么差别。(ps:既然这么设计,那一定是有区别的)。 在平时的开发中,我们通常在控制层采用注解Controller,在业务层采用注解Service。spring在启动时,有一个非常核心的类ConfigurationClassPostProcessor会对类路径下的所以类进行扫描,将符合条件的bean扫描出来添加到beanDefinitionMap集合中,方便接下来的实例化。具体的扫描过程比较复杂,仅仅贴出核心判断逻辑代码。 org。springframework。core。type。filter。AnnotationTypeFilterprotectedbooleanmatchSelf(MetadataReadermetadataReader){AnnotationMetadatametadatametadataReader。getAnnotationMetadata();returnmetadata。hasAnnotation(this。annotationType。getName())(this。considerMetaAnnotationsmetadata。hasMetaAnnotation(this。annotationType。getName()));} 代码解释: (1)this。annotationType。getName():获取的是注解Component的全路径名org。springframework。stereotype。Component。 (2)metadata。hasAnnotation(this。annotationType。getName()):判断当前的类是否直接采用注解Component。 (3)metadata。hasMetaAnnotation(this。annotationType。getName()):如果当前的类没有直接采用Component,而是采用了类组合注解Controller,判断组合注解Controller中是否包含Component。 至此,所有添加了注解Controller、Service和Component都被spring扫描出来了。(ps:这就说明了其实在扫描的时候spring其实将这三个注解都按照Component进行扫描的)Controller分析 如果不使用springMVC时,三者使用其实是没有什么差别的,但如果使用了springMVC,Controller就被赋予了特殊的含义。 spring会遍历上面扫描出来的所有bean,过滤出那些添加了注解Controller的bean,将Controller中所有添加了注解RequestMapping的方法解析出来封装成RequestMappingInfo存储到RequestMappingHandlerMapping中的mappingRegistry。后续请求到达时,会从mappingRegistry中查找能够处理该请求的方法。 部分核心代码如下: org。springframework。web。reactive。result。method。annotation。RequestMappingHandlerMappingprotectedbooleanisHandler(C?beanType){判断扫描出来的bean是否包含注解Controller,如果包含,springMVC会将其封装为RequestMappingInforeturn(AnnotatedElementUtils。hasAnnotation(beanType,Controller。class)AnnotatedElementUtils。hasAnnotation(beanType,RequestMapping。class));}privateRequestMappingInfocreateRequestMappingInfo(AnnotatedElementelement){判断传递进来的方法是否包含RequestMapping,如果包含,就将其封装成RequestMappingInfoRequestMappingrequestMappingAnnotatedElementUtils。findMergedAnnotation(element,RequestMapping。class);RequestC?condition(elementinstanceofClass?getCustomTypeCondition((C?)element):getCustomMethodCondition((Method)element));return(requestMapping!null?createRequestMappingInfo(requestMapping,condition):null);}Service分析 目前Service本人没有找到其特殊之处,可能spring官方后续会添加特殊的操作吧。Component分析 该注解是万能的注解,通常加在配置类上。小结 实际上有一个注解本文没有具体讲解,它就是Repository,由于本人没有亲自验证,所以就没有进行分析,怕误导大家。有具体分析并验证过的网友,大家可以一起探讨。 如果有小伙伴也想验证,可以将断点打在我在文中贴出来的三段核心代码处,在spring启动的时候可以进行调试。具体的代码调用逻辑,可能会在以后的文章中进行分析。