Spring源码之注解的原理

时间:2023-03-10 05:17:12
Spring源码之注解的原理

https://blog.****.net/qq_28802119/article/details/83573950

https://www.zhihu.com/question/318439660/answer/639644735

https://blog.****.net/u014534808/article/details/81071452

https://www.cnblogs.com/lxyit/p/10210581.html

https://www.cnblogs.com/lipengsheng-javaweb/p/12888842.html

https://www.zhihu.com/question/24401191

https://www.cnblogs.com/yangming1996/p/9295168.html(最好的一篇)

https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.6(官网)

JDK注解原理

原理总结:所有的注解都继承了Annotation接口,而注解类什么的注解,属于类中attribute。被注解修饰的类,在运行时会生成一个代理类(RetentionPolicy.RUNTIME),重写继承而来所有方法,从而实现功能。

所有注解都继承了annotation,打开任意注解类,用jclasslib查看便能看到:

Access flags: 0x... [public interface abstract annotation]

Spring源码之注解的原理

而在这个继承Annotation的注解类上面的注解,则属于这个类的Attributes

属性表有以下几种:

RuntimeVisibleAnnotations:运行时可见的注解

RuntimeInVisibleAnnotations:运行时不可见的注解

RuntimeVisibleParameterAnnotations:运行时可见的方法参数注解

RuntimeInVisibleParameterAnnotations:运行时不可见的方法参数注解

AnnotationDefault:注解类元素的默认值

所以在Class.forName(name, false, clToUse)进行反射时,便能获取此类上面annotation属性

而当要去获取一个注解类实例时(如调用getAnnotation),便会生成一个代理类。重写其所有方法,包括 value 方法以及自定义接口从 Annotation 接口继承而来的方法

自定义注解类:

import org.springframework.stereotype.Component;
import java.lang.annotation.*; @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface MyComponent {
}

测试类:

@MyComponent
public class AnnotationTest {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
MyComponent annotation = AnnotationTest.class.getAnnotation(MyComponent.class);
System.out.println(annotation.annotationType());
}
}

生成的代理类:

public final class $Proxy0 extends Proxy implements Retention {
... public final Class annotationType() throws {
try {
return (Class)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final RetentionPolicy value() throws {
try {
return (RetentionPolicy)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} ...
}
public final class $Proxy1 extends Proxy implements MyComponent {
... public final String test() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final Class annotationType() throws {
try {
return (Class)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} ...
}

@TODO: 为何生成两个代理类

Spring中注解

createApplicationContext()时registerDefaultFilters

调用链:

SpringApplication#run() --> SpringApplication#createApplicationContext() --> new AnnotationConfigServletWebServerApplicationContext() --> ClassPathBeanDefinitionScanner# --> ClassPathScanningCandidateComponentProvider#registerDefaultFilters()

在registerDefaultFilters中会注册默认两个includerFilters(Component和ManagedBean)

protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
......
}

同样断点,可查看到会将ComponentScanAnnotationParser、AutoConfigurationExcludeFilter、TypeExcludeFilter加入excludeFilters

获取MetadataReader

调用链:

AbstractApplicationContext#refresh() --> AbstractApplicationContext#invokeBeanFactoryPostProcessors() --> PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() --> PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors() --> ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()--> ConfigurationClassPostProcessor#processConfigBeanDefinitions() --> ConfigurationClassPostProcessor#parse() --> ConfigurationClassPostProcessor#processConfigurationClass() -->

ConfigurationClassParser#parse() -->

ConfigurationClassParser#doProcessConfigurationClass() -->

ComponentScanAnnotationParser#parse() --> ClassPathBeanDefinitionScanner#doScan() --> ClassPathScanningCandidateComponentProvider#findCandidateComponents() --> ClassPathScanningCandidateComponentProvider#scanCandidateComponents --> CachingMetadataReaderFactory#getMetadataReader() --> SimpleMetadataReaderFactory#getMetadataReader()--> SimpleMetadataReader# -->ClassReader#accept()

在ClassReader类中依赖ASM字节码库实现,通过反射获取类所有信息。注解信息在类的attribute中

/**
* Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
* {@link ClassReader}.
*
* @param classVisitor the visitor that must visit this class.
* @param attributePrototypes prototypes of the attributes that must be parsed during the visit of
* the class. Any attribute whose type is not equal to the type of one the prototypes will not
* be parsed: its byte array value will be passed unchanged to the ClassWriter. <i>This may
* corrupt it if this value contains references to the constant pool, or has syntactic or
* semantic links with a class element that has been transformed by a class adapter between
* the reader and the writer</i>.
* @param parsingOptions the options to use to parse this class. One or more of {@link
* #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
*/
@SuppressWarnings("deprecation")
public void accept(
final ClassVisitor classVisitor,
final Attribute[] attributePrototypes,
final int parsingOptions) {
...... // Visit the RuntimeVisibleAnnotations attribute.
if (runtimeVisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
} // Visit the RuntimeVisibleTypeAnnotations attribute.
if (runtimeVisibleTypeAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the target_type, target_info and target_path fields.
currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
/* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
} ...... // Visit the end of the class.
classVisitor.visitEnd();
}
判断是否满足@Component条件
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}

不在excludeFilters,并且在includeFilters中

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
/**
* Determine whether the given bean definition qualifies as candidate.
* <p>The default implementation checks whether the class is not an interface
* and not dependent on an enclosing class.
* <p>Can be overridden in subclasses.
* @param beanDefinition the bean definition to check
* @return whether the bean definition qualifies as a candidate component
*/
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
@Inherite

https://www.jianshu.com/p/7f54e7250be3

类继承关系中@Inherited的作用

类继承关系中,子类会继承父类使用的注解中被@Inherited修饰的注解

接口继承关系中@Inherited的作用

接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有被@Inherited修饰

类实现接口关系中@Inherited的作用

类实现接口时不会继承任何接口中定义的注解

TODO

一种是编译期直接的扫描,一种是运行期反射