1. Java注解
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种正文机制。
Java语言中的类、办法、变量、参数和包等都能够被标注。
在编译器生成类文件时,标注能够被嵌入到字节码中
因而Java虚拟机能够在运行时能够通过反射获取到标注内容。
2. 元注解
JDK中提供了一些根底注解,称为元注解。最常见的几种比方:
作用在代码上的:
- @Override - 查看该办法是否是重写办法。如果发现其父类,或者是援用的接口中并没有该办法时,会报编译谬误。
- @Deprecated - 标记过期办法。如果应用该办法,会报编译正告。
- @SuppressWarnings - 批示编译器去疏忽注解中申明的正告。
作用在其余注解的:
- @Retention - 标识这个注解怎么保留,是只在代码中(SOURCE),还是编译入class文件中(CLASS),或者是在运行时能够通过反射拜访(RUNTIME)。
- @Documented - 标记这个注解是否蕴含在JavaDoc中。
- @Target - 标记这个注解应该润饰哪种 Java 成员。
- @Inherited - 标记如果一个类具备继承注解,那么他所有的子类也领有该注解
后续新退出的:
- @SafeVarargs - Java 7 开始反对,疏忽任何应用参数为泛型变量的办法或结构函数调用产生的正告。
- @FunctionalInterface - Java 8 开始反对,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始反对,标识某注解能够在同一个申明上应用屡次。
这里不对元注解进行具体的介绍,有须要的能够去查阅相干的文档。
3. 自定义注解
Java容许咱们实现自定义注解来实现某些性能。
总的来说,自定义注解须要实现3步:定义注解、标注注解、解决注解
(1) 定义注解
应用@interface来定义一个注解,上面定义了一个名为MyAnnotation的注解。
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface MyAnnotation { String value() default "MyAnnotation";}
@Retention(RetentionPolicy.RUNTIME)示意该注解在运行时也无效,这样就能够应用反射的形式来获取到。
@Target(ElementType.TYPE)示意该注解是用在类或者接口上的
(2) 标注注解
@MyAnnotation("test")public class MyClass1 { }@MyAnnotationpublic class MyClass2 { }
这里实现了两个类,别离应用MyAnnotation进行注解,MyClass1的注解中配置了属性值test,MyClass2没有配置属性值。
(3) 解决注解
public class MyClassTest { @Test public void test() { new ApplicationContextRunner().withBean(MyClass1.class).withBean(MyClass2.class).run(context -> { // 获取所有被MyAnnotation标注的类 Map<String, Object> beansWithAnnotation = context.getBeansWithAnnotation(MyAnnotation.class); for (Map.Entry<String, Object> entry : beansWithAnnotation.entrySet()) { System.out.println("BeanName is " + entry.getKey()); // 获取类上的MyAnnotation标注 MyAnnotation annotation = entry.getValue().getClass().getAnnotation(MyAnnotation.class); System.out.println("the value of annotation is " + Objects.requireNonNull(annotation).value()); } }); }}
这里实现了一个测试类,依据注解的属性值的不同,打印不同的内容。
运行后果:
能够看到MyClass1打印出了设置的test,MyClass2打印出了默认的MyAnnotation。
4. 自定义条件注解
@Conditional是一个很罕用的注解,用来依据肯定的条件判断,是否给容器注入Bean的。
而@ConditionalOnProperty、@ConditionalOnClass等都是通过组合@Conditional,提供了更弱小的性能。
接下来咱们通过组合@Conditional,实现一个当属性name的值只有属于配置数组中的时候,就实现Bean的注入。
(1) 定义注解
定义一个ConditionalOnContains注解
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Conditional(ContainsCondition.class)public @interface ConditionalOnContains { int[] value();}
@Target(ElementType.METHOD)示意该注解是用在办法上的
(2) 标注注解
public class ContainsConfiguration { @Bean @ConditionalOnContains(value = {0, 1}) public ContainsTest1 containsTest1() { return new ContainsTest1(); } @Bean @ConditionalOnContains(value = {1, 2}) public ContainsTest2 containsTest2() { return new ContainsTest2(); } @Bean @ConditionalOnContains(value = {2, 3}) public ContainsTest3 containsTest3() { return new ContainsTest3(); }}
这里实现了三个类,别离应用ConditionalOnContains进行注解,ContainsTest1的注解中配置了value = {0,1}, ContainsTest2的注解中配置了value = {1,2}, ContainsTest3的注解中配置了value = {2,3}。
(3) 解决注解
public class ContainsCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes( ConditionalOnContains.class.getName()); int[] values = (int[]) Objects.requireNonNull(annotationAttributes).get("value"); for (int value : values) { if (value == 1) { return true; } } return false; }}
这里对注解的属性值进行解决,如果蕴含1,则返回true,否则返回false.
运行后果:
能够看到打印出了containsTest1和containsTest2,而没有打印containsTest3,因为其value属性值不蕴含1.