网站首页 > 技术教程 正文
今天主要聊聊@Controller 、@Service和@Component这三个注解的关系和区别。网上很多人对这三个注解进行了详细的解释,但是仅仅局限于理论,个人对于没有经过自己验证的结果总是持怀疑态度,所有花时间研究了一下,也对这三个注解理解的更加透彻。(ps:网上好多回答不一定正确,所以只能自己花时间验证)
附上三个注解的源代码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // 关键注解
public @interface Controller {
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // 关键注解
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}
注解扫描
首先说说这三个注解的关系,从源码中可以看出,@Controller和@Service都派生于@Component,所以三者的使用方式基本没什么差别。(ps:既然这么设计,那一定是有区别的)。
在平时的开发中,我们通常在控制层采用注解@Controller,在业务层采用注解@Service。spring在启动时,有一个非常核心的类ConfigurationClassPostProcessor会对类路径下的所以类进行扫描,将符合条件的bean扫描出来添加到beanDefinitionMap集合中,方便接下来的实例化。具体的扫描过程比较复杂,仅仅贴出核心判断逻辑代码。
org.springframework.core.type.filter.AnnotationTypeFilter
protected boolean matchSelf(MetadataReader metadataReader) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
return metadata.hasAnnotation(this.annotationType.getName()) ||
(this.considerMetaAnnotations && metadata.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.RequestMappingHandlerMapping
protected boolean isHandler(Class<?> beanType) {
// 判断扫描出来的bean是否包含注解@Controller,
// 如果包含,springMVC会将其封装为RequestMappingInfo
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
// 判断传递进来的方法是否包含@RequestMapping,
// 如果包含,就将其封装成RequestMappingInfo
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);
}
@Service分析
目前@Service本人没有找到其特殊之处,可能spring官方后续会添加特殊的操作吧。
@Component分析
该注解是万能的注解,通常加在配置类上。
小结
实际上有一个注解本文没有具体讲解,它就是@Repository,由于本人没有亲自验证,所以就没有进行分析,怕误导大家。有具体分析并验证过的网友,大家可以一起探讨。
如果有小伙伴也想验证,可以将断点打在我在文中贴出来的三段核心代码处,在spring启动的时候可以进行调试。具体的代码调用逻辑,可能会在以后的文章中进行分析。
猜你喜欢
- 2025-01-12 Spring Boot RESTful API设计:最佳实践指南
- 2025-01-12 由 Mybatis 源码畅谈软件设计(二):MappedStatement 和 SqlSource
- 2025-01-12 详细介绍一下Spring Boot中如何使用Hive?
- 2025-01-12 OGG同步到Kafka
- 2025-01-12 由 Mybatis 源码畅谈软件设计(五):ResultMap 的循环引用
- 2025-01-12 【从零开始】5. 向量数据库选型与搭建
- 2025-01-12 Spring Boot 项目轻松集成 Redis
- 2025-01-12 How China's Drone Manufacturers Leapfrog From Latecomers to Global Leaders
- 2025-01-12 Spring Boot与MyBatis:简化数据库操作
- 2025-01-12 SpringBoot整合ElasticSearch实现数据存储?
你 发表评论:
欢迎- 01-12Spring Boot RESTful API设计:最佳实践指南
- 01-12由 Mybatis 源码畅谈软件设计(二):MappedStatement 和 SqlSource
- 01-12详细介绍一下Spring Boot中如何使用Hive?
- 01-12OGG同步到Kafka
- 01-12由 Mybatis 源码畅谈软件设计(五):ResultMap 的循环引用
- 01-12【从零开始】5. 向量数据库选型与搭建
- 01-12Spring Boot 项目轻松集成 Redis
- 01-12How China's Drone Manufacturers Leapfrog From Latecomers to Global Leaders
- 最近发表
-
- Spring Boot RESTful API设计:最佳实践指南
- 由 Mybatis 源码畅谈软件设计(二):MappedStatement 和 SqlSource
- 详细介绍一下Spring Boot中如何使用Hive?
- OGG同步到Kafka
- 由 Mybatis 源码畅谈软件设计(五):ResultMap 的循环引用
- 【从零开始】5. 向量数据库选型与搭建
- Spring Boot 项目轻松集成 Redis
- How China's Drone Manufacturers Leapfrog From Latecomers to Global Leaders
- Spring Boot与MyBatis:简化数据库操作
- SpringBoot整合ElasticSearch实现数据存储?
- 标签列表
-
- sd分区 (65)
- raid5数据恢复 (81)
- 地址转换 (73)
- 手机存储卡根目录 (55)
- tcp端口 (74)
- project server (59)
- 双击ctrl (55)
- 鼠标 单击变双击 (67)
- debugview (59)
- 字符动画 (65)
- flushdns (57)
- ps复制快捷键 (57)
- 清除系统垃圾代码 (58)
- web服务器的架设 (67)
- 16进制转换 (69)
- xclient (55)
- ps源文件 (67)
- filezilla server (59)
- 句柄无效 (56)
- word页眉页脚设置 (59)
- ansys实例 (56)
- 6 1 3固件 (59)
- sqlserver2000挂起 (59)
- vm虚拟主机 (55)
- config (61)
本文暂时没有评论,来添加一个吧(●'◡'●)