Spring之注解实现原理深度解析

概述

Spring框架的核心就是IOC,通过controller一类注解的bean的实例化过程可以大体总结spring注解的工作原理:

1)利用asm技术扫描class文件,转化成Springbean结构,把符合扫描规则的(主要是是否有相关的注解标注,例如@Component)bean注册到Spring 容器中beanFactory。

2)注册处理器,包括注解处理器

3)实例化处理器(包括注解处理器),并将其注册到容器的beanPostProcessors列表中。

4)创建bean的过程中,属性注入或者初始化bean时会调用对应的注解处理器进行处理。

例如注解@Autowired:

对于这个注解,您需要在xml中配置这个注解的处理器AutowiredAnnotationBeanPostProcessor,这个处理器会扫描容器中所有的bean对象,发现bean中拥有@Autowired注解的时候会自动去找到容器中和这个注解修饰类型匹配的bean对象,并注入到对应的地方去。

元注解

  • @Target:表示该注释可以用于什么地方,下面是源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Documented
    @Retention(RetentionPolicy.RUNTIME) // 保留到运行时
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
    /**
    * Returns an array of the kinds of elements an annotation type
    * can be applied to.
    * @return an array of the kinds of elements an annotation type
    * can be applied to.
    */
    ElementType[] value();
    }

    注解作用位置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public enum ElementType {
    TYPE, // 类,接口(包括注解),enum;
    FIELD, // 属性域
    METHOD, // 方法
    PARAMETER, // 参数
    CONSTRUCTOR, // 构造函数
    LOCAL_VARIABLE, // 局部变量
    ANNOTATION_TYPE, // 注解类型
    PACKAGE, // 包

    /**
    * Type parameter declaration
    * @since 1.8
    */
    TYPE_PARAMETER, // 表明可以标注 类型参数

    /**
    * Use of a type
    * @since 1.8
    */
    TYPE_USE // 可以注解 任何类型名称
    }
  • @Retention 表示需要在什么级别保存该注释信息,下面是源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /* Indicates how long annotations with the annotated type are to
    * be retained. If no Retention annotation is present on
    * an annotation type declaration, the retention policy defaults to
    * {@code RetentionPolicy.CLASS}.
    *
    * A Retention meta-annotation has effect only if the
    * meta-annotated type is used directly for annotation. It has no
    * effect if the meta-annotated type is used as a member type in
    * another annotation type.
    */
    @Documented // 表明 注解会被包含在Java API文档中。
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
    /**
    * Returns the retention policy.
    * @return the retention policy
    */
    RetentionPolicy value();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public enum RetentionPolicy {
    /**
    * Annotations are to be discarded by the compiler.
    */
    SOURCE,

    /**
    * Annotations are to be recorded in the class file by the compiler
    * but need not be retained by the VM at run time. This is the default
    * behavior.
    */
    CLASS,

    /**
    * Annotations are to be recorded in the class file by the compiler and
    * retained by the VM at run time, so they may be read reflectively.
    *
    * @see java.lang.reflect.AnnotatedElement
    */
    RUNTIME
    }

    RetentionPolicy.SOURCE 保留在源码级别,被编译器抛弃,如@Override;
    RetentionPolicy.CLASS 被编译器保留在编译后的class文件,但是被VM抛弃;
    RetentionPolicy.RUNTIME 保留至运行时,可以被反射读取。如 @Retention 元注解本身。

  • @Documented 将注释包含在JavaDoc中

  • @Inheried 允许子类继承父类中的注解

Java如何识别注解

关键词:Java反射

java.lang.reflect 包,实现反射功能的工具类

注解处理类库:java.lang.reflect.AnnotatedElement

zhujie2

zhujie3

程序通过反射获取了某个类的AnnotatedElement对象之后, 程序就可以调用该对象如下的方法来访问Annotation的信息:

  • Annotation[] getAnnotations()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**
    * Returns annotations that are <em>present</em> on this element.
    *
    * If there are no annotations <em>present</em> on this element, the return
    * value is an array of length 0.
    *
    * The caller of this method is free to modify the returned array; it will
    * have no effect on the arrays returned to other callers.
    *
    * @return annotations present on this element
    * @since 1.5
    */
    Annotation[] getAnnotations();
  • default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
    * Returns true if an annotation for the specified type
    * is <em>present</em> on this element, else false. This method
    * is designed primarily for convenient access to marker annotations.
    *
    * <p>The truth value returned by this method is equivalent to:
    * {@code getAnnotation(annotationClass) != null}
    *
    * <p>The body of the default method is specified to be the code
    * above.
    *
    * @param annotationClass the Class object corresponding to the
    * annotation type
    * @return true if an annotation for the specified annotation
    * type is present on this element, else false
    * @throws NullPointerException if the given annotation class is null
    * @since 1.5
    */
    default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
    return getAnnotation(annotationClass) != null;
    }
  • default T getDeclaredAnnotation(Class annotationClass)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    /**
    * Returns this element's annotation for the specified type if
    * such an annotation is <em>directly present</em>, else null.
    *
    * This method ignores inherited annotations. (Returns null if no
    * annotations are directly present on this element.)
    *
    * @implSpec The default implementation first performs a null check
    * and then loops over the results of {@link
    * #getDeclaredAnnotations} returning the first annotation whose
    * annotation type matches the argument type.
    *
    * @param <T> the type of the annotation to query for and return if directly present
    * @param annotationClass the Class object corresponding to the
    * annotation type
    * @return this element's annotation for the specified annotation type if
    * directly present on this element, else null
    * @throws NullPointerException if the given annotation class is null
    * @since 1.8
    */
    default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
    Objects.requireNonNull(annotationClass);
    // Loop over all directly-present annotations looking for a matching one
    for (Annotation annotation : getDeclaredAnnotations()) {
    if (annotationClass.equals(annotation.annotationType())) {
    // More robust to do a dynamic cast at runtime instead
    // of compile-time only.
    return annotationClass.cast(annotation);
    }
    }
    return null;
    }

为了处理注解,注解处理器做3件事情:

  • 读取配置文件中管理的bean
  • 实例化bean
  • 注解处理器获取实例bean中的注解并操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 自定义的注解处理器
public class ClassPathXMLApplicationContext {

public ClassPathXMLApplicationContext(String configFileName) {
// 读取配置文件中管理的bean
readXMLConfigFile(configFileName);
// 实例化bean
instanceBean();
// 向容器注册bean
registerAnnotationBean();
}

// 读取配置文件中的bean
private void readXMLConfigFile() {

}

// 实例化bean
private void instanceBean() {

}

// 向容器注册bean
private void registerAnnotationBean() {

}
}

Spring是如何实现注解的扫描注册的

管理注解bean定义的两个容器:

  • AnnotationConfigApplicationContext
  • AnnotationConfigWebApplicationContext

AnnotationConfigApplicationContext的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package org.springframework.context.annotation;

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
// 读取器:读取注解的Bean,并注册到容器中。
private final AnnotatedBeanDefinitionReader reader;
// 扫描器:扫描类路径中注解的Bean,并注册到容器中。
private final ClassPathBeanDefinitionScanner scanner;

public AnnotationConfigApplicationContext() {
// reader和scanner,功能类似,使用场景不同:annotatedClasses, basePakages.
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

/*********************************
* 1 区
***/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}

public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
/*********************************/
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}

public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.reader.setBeanNameGenerator(beanNameGenerator);
this.scanner.setBeanNameGenerator(beanNameGenerator);
getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}

public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
this.reader.setScopeMetadataResolver(scopeMetadataResolver);
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
}

/***************************
* 2 区
***/
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}

public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
/***************************/
@Override
protected void prepareRefresh() {
this.scanner.clearCache();
super.prepareRefresh();
}
}

AnnotationCnofigApplicationContext类的源码中的 “1 区”:

AnnotationConfigApplicationContext的基本功能在构造函数中完成

实例化reader和scanner,然后调用 register(Class<?>… annotatedClasses)或scan(String… basePackages)方法,最后刷新。

register(Class<?>… annotatedClasses)方法调用reader.register(Class<?>… annotatedClasses)

scan(String… basePackages)方法调用scanner.scan(String… basePackages)

AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 功能类似,二者取其一。

AnnotationConfigApplicationContext 类的源码中的 “2 区”:

如下两个方法完成了Spring的扫描注册功能

reader.register(Class<?>… annotatedClasses)

scanner.scan(String… basePackages)

  • reader.register(Class<?>… annotatedClasses) 的源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    public void register(Class<?>... annotatedClasses) {
    for (Class<?> annotatedClass : annotatedClasses) {
    registerBean(annotatedClass);
    }
    }

    public void registerBean(Class<?> annotatedClass) {
    registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null);
    }


    // 注解功能实现区
    @SuppressWarnings("unchecked")
    public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    return;
    }

    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    abd.setScope(scopeMetadata.getScopeName());
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    if (qualifiers != null) {
    for (Class<? extends Annotation> qualifier : qualifiers) {
    if (Primary.class == qualifier) {
    abd.setPrimary(true);
    } else if (Lazy.class == qualifier) {
    abd.setLazyInit(true);
    } else {
    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
    }
    }
    }

    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }
  • scanner.scan(String… basePackages) 源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    public int scan(String... basePackages) {
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

    doScan(basePackages); // 备注:重点关注此处

    // Register annotation config processors, if necessary.
    if (this.includeAnnotationConfig) {
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }


    // 注解功能实现区
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    /**
    * BeanDefinitionHoder: Holder for a BeanDefinition with name and aliases.
    * BeanDefinition: A BeanDefinition describes a bean instance,
    * which has property values, constructor argument values, and
    * further information supplied by concrete implementations.
    */
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
    for (String basePackage : basePackages) { // 多个包路径
    Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    for (BeanDefinition candidate : candidates) {
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    candidate.setScope(scopeMetadata.getScopeName());
    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    if (candidate instanceof AbstractBeanDefinition) {
    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    }
    if (candidate instanceof AnnotatedBeanDefinition) {
    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    }
    if (checkCandidate(beanName, candidate)) {
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    beanDefinitions.add(definitionHolder);
    registerBeanDefinition(definitionHolder, this.registry);
    }
    }
    }
    return beanDefinitions;
    }

总结

zhujie1

秉持初心,继续向前。
显示 Gitment 评论