背景:
spring注解方式进行依赖注入,是SpringBoot得以实现的幕后推手。因此需要对java注解进行多一些的了解。
1. 元注解@Retention
java.lang.annotation.Retention表示注解在哪些范围生效。
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
}
SOURCE:java编译后丢弃,在class文件中就没有这个注解了。 (如lombok的注解就是SOURCE)
CLASS: java编译后保留,jvm加载后丢弃。jvm运行后无法通过反射获取此注解信息 (org.mapstruct.Mapper注解就是CLASS范围)
RUNTIME: java编译后保留,jvm加载后也存在。jvm运行后能够通过反射获取此注解信息2. 2. 2(spring框架的注解基本都是RUNTIME)
2.元注解@Target
java.lang.annotation.Target表示修饰的注解可以用在哪些地方。
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE,
/**
* Module declaration.
*
* @since 9
*/
MODULE
}
3. 复合注解是如何解析的:
org.springframework.boot.autoconfigure.SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@SpringBootApplication
public class AnnotationDemo {
/**
* 组合注解的解析方法
*/
@Test
public void combineAnnotation() {
AnnotationDemo demo = new AnnotationDemo();
Class clazz = demo.getClass();
for (Annotation annotation : clazz.getAnnotations()) {
System.out.println(annotation);
System.out.println("-----------");
Arrays.stream(annotation.annotationType().getAnnotations())
.forEach(System.out::println);
}
}
}
日志输出:
@org.springframework.boot.autoconfigure.SpringBootApplication(scanBasePackageClasses={}, nameGenerator=org.springframework.beans.factory.support.BeanNameGenerator.class, proxyBeanMethods=true, excludeName={}, exclude={}, scanBasePackages={})
-----------
@java.lang.annotation.Target(value={TYPE})
@java.lang.annotation.Retention(value=RUNTIME)
@java.lang.annotation.Documented()
@java.lang.annotation.Inherited()
@org.springframework.boot.SpringBootConfiguration(proxyBeanMethods=true)
@org.springframework.boot.autoconfigure.EnableAutoConfiguration(excludeName={}, exclude={})
@org.springframework.context.annotation.ComponentScan(scopeResolver=org.springframework.context.annotation.AnnotationScopeMetadataResolver.class, lazyInit=false, resourcePattern="**/*.class", excludeFilters={@org.springframework.context.annotation.ComponentScan$Filter(pattern={}, type=CUSTOM, value={}, classes={org.springframework.boot.context.TypeExcludeFilter.class}), @org.springframework.context.annotation.ComponentScan$Filter(pattern={}, type=CUSTOM, value={}, classes={org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter.class})}, useDefaultFilters=true, scopedProxy=DEFAULT, basePackageClasses={}, nameGenerator=org.springframework.beans.factory.support.BeanNameGenerator.class, basePackages={}, includeFilters={}, value={})