zoukankan      html  css  js  c++  java
  • Spring 注解编程之模式注解

    Spring 框架中有很多可用的注解,其中有一类注解称模式注解(Stereotype Annotations),包括 @Component@Service,@Controller,@Repository 等。只要在相应的类上标注这些注解,就能成为 Spring 中组件(Bean)。

    需要配置开启自动扫描。如在 XML 中配置 <context:component-scan base-package="xxx.xxx.xx"/>` 或使用注解 @ComponentScan。

    从最终的效果上来看,@Component@Service,@Controller,@Repository 起到的作用完全一样,那为何还需要多个不同的注解?

    从官方 wiki 我们可以看到原因。

    stereotype annotation is an annotation that is used to declare the role that a component plays within the application. For example, the @Repository annotation in the Spring Framework is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO).

    不同的模式注解虽然功能相同,但是代表含义却不同。

    标注@Controller 注解,这类组件就可以表示为 WEB 控制层 ,处理各种 HTTP 交互。标注 @Service 可以表示为内部服务层 ,处理内部服务各种逻辑。而 @Repository 可以代表示为数据控制层,代表数据库增删改查动作。

    这样一来不同模式注解带来了不同的含义,清晰将服务进行分层。

    除了上面的作用,特定的模式注解,Spring 可能会在未来增加额外的功能语义。如现在 @Repository 注解,可以增加异常的自动转换功能

    所以,对于分层服务最好使用各自特定语义的模式注解,如 WEB 层就使用 @Controller注解。

    模式注解原理

    在 Spring 中任何标注 @Component 的组件都可以成为扫描的候选对象。另外任何使用 @Component 标注的注解,如 @Service,当其标注组件时,也能被当做扫描的候选对象。。

    @Component is a generic stereotype for any Spring-managed component. Any component annotated with @Component is a candidate for component scanning. Similarly, any component annotated with an annotation that is itself meta-annotated with @Component is also a candidate for component scanning. For example, @Service is meta-annotated with @Component.

    @service

    如果想使自定义的注解也能如 @Service 注解功能一样,只要在自定义注解上标注 @Component 就可以。

    AnnotationMetadata

    从上面文档看出只要在类上存在 @Component注解,即使存在于注解的注解上,Spring 都将能其成为候选组件。

    注解上的注解 Spring 将其定义为元注解(meta-annotation),如 @Component标注在 @Service上,@Component 就被称作为元注解。后面我们就将注解的注解称为元注解。

    meta-annotation is an annotation that is declared on another annotation. An annotation is therefore meta-annotated if it is annotated with another annotation. For example, any annotation that is declared to be documented is meta-annotated with @Documented from thejava.lang.annotation package.

    那么对于一个类是否可以成为 Spring 组件,需要判断这个类是否包含 @Component 注解,或者类上元注解中是否包含 @Component

    在 Spring 中可以通过 MetadataReader 获取 ClassMetadata 以及 AnnotationMetadata,然后获取相应元数据。

    ClassMetadata 可以获取类的各种元数据,比如类名,接口等。

    ClassMetadata

    AnnotationMetadata 可以获取当前类上注解的元数据,如注解名字,以及元注解信息等。

    AnnotationMetadata

    所以只要获取到 AnnotationMetadata,就可以判断是否存在 @Component。判断方式如下

    判断是否存在 Component

    获取 AnnotationMetadata

    这里我们从 XML 配置开启扫描开始讲起。

    <context:component-scan base-package="xxx.xxx.xx"/>

    首先在 META-INF 下查找 spring.handles 文件。

    不明白小伙伴们可以查看上一篇文章 缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制

    image.png

    context 标签在 ContextNamespaceHandler 注册 XML 解析器。在 ContextNamespaceHandler中其使用了 ComponentScanBeanDefinitionParser真正解析 XML。

    ContextNamespaceHandler 源码

    ComponentScanBeanDefinitionParser#parse 方法中,首先获取 XML 中配置 base-package属性,获取扫描的范围,然后调用 ClassPathBeanDefinitionScanner#doScan 获取 base-package 所有 BeanDefinition

    ComponentScanBeanDefinitionParser#parse

    doScan 方法中最终会调用ClassPathScanningCandidateComponentProvider#scanCandidateComponents 获取扫描范围内所有 BeanDefinition

    scanCandidateComponents 中首先获取扫描包范围内资源对象,然后迭代从可读取资源对象中MetadataReaderFactory#getMetadataReader(resource)获取MetadataReader` 对象。

    上文已经讲到 MetadataReader 对象作用,这里查看如何使用MetadataReader 进行判断。

    筛选组件

    isCandidateComponent方法中将会传入 MetadataReaderTypeFilter#match进行判断。

    条件的判断主要使用 excludeFiltersincludeFilters 两个字段决定。那两个字段从何处生成?

    原来在ComponentScanBeanDefinitionParser中调用 ClassPathBeanDefinitionScanner构造方法时,默认传入 useDefaultFilters=true

    构造方法

    registerDefaultFilters 注册默认的过滤器,生成 excludeFiltersincludeFilters 初始值。

    默认情况下,excludeFilters 将会是个空集,而 includeFilters 集合中增加一个包含@Component 类型信息的 AnnotationTypeFilter 实例,以及另外两个包含 Java EE 注解AnnotationTypeFilter 实例。

    跳到 AnnotationTypeFilter#match 方法中。AnnotationTypeFilter 类图如下。

    image.png

    AnnotationTypeFilter#match 方法在抽象类 AbstractTypeHierarchyTraversingFilter中实现。

    match

    match 方法首先调用了 matchSelf,而该方法最终由 AnnotationTypeFilter 重写。

    可以看到这里最终使用 AnnotationMetadata 方法判断是否存在指定注解。

    源码分析就到此为止,下篇文章将会深入 AnnotationMetadata,查看其实如何获取元数据的。

    帮助文档

    Spring Annotation Programming Model
    beans-stereotype-annotations
    『Spring Boot 编程思想』

    其他平台.png

  • 相关阅读:
    牛客小白赛23
    三分查找模板和例题
    链式前向星存图模板
    树形dp求解树的重心和例题
    P3915-树的分解-(dfs)
    P2119 魔法阵-(桶排序+前后缀和)
    小阳的贝壳-(差分+线段树+gcd)
    NOJ1370: [蓝桥杯2018初赛]测试次数-(dp)
    begin.lydsy 入门OJ题库:3611-3613:神炎皇、降雷皇、幻魔皇
    1797: [Noi2010]海拔
  • 原文地址:https://www.cnblogs.com/goodAndyxublog/p/11115345.html
Copyright © 2011-2022 走看看