meta-annotation元注解(@Target @Retention @Documented @Inherited)

开场白

要能够写自己的注解,一定要了解Java为我们提供的元注解和相关定义注解的语法。
一. 元注解(meta-annotation)
元注解的作用就是负责注解其他注解,这是Java 5.0就开始定义的标准,它们被用来提供对其他annotation类型作说明。

  1. @Target
  2. @Retention
  3. @Document
  4. @Inherited

@Target
@Target说明了Annotation所修饰的对象范围:可被用于packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量。在Annotation类型的声明中使用了target可更加明确其修饰的目标。
作用:描述注解的使用范围;
取值: 1. CONSTRUCTOR:用于描述构造器
2. FIELD:用于描述域;
3. LOCAL_VARIABLE:用于描述局部变量;
4. METHOD:用于描述方法;
5. PACKAGE:用于描述包;
6. PARAMETER:用于描述参数;
7. TYPE:用于描述类、接口(包括注解类型)、枚举类型

@Target(ElementType.TYPE)
public @interface Table {
		public String tableName() default "tableName";
}

@Target(ElementType.FIELD)
public @interface DB {
}

上面的例子Table注解可用于类、接口或者枚举类型,而DB注解仅可用于注解使用类的成员变量。

@Retention
@Retention 定义了该Annotation保留的时间:某些Annotation仅出现在源代码中,而被编译器丢弃;有一些却在被便衣的class文件中;便衣在class文件中的Annotation可能会被虚拟机忽略,而另外一些class被加载时将被读取。使用@Retention注解可以对Annotation的生命周期进行限制。
作用:用于描述注解的生命周期,需要在什么时候什么级别保留该注解信息;
取值:1. SOURCE:在源文件中有效;
2. CLASS:在class文件中有效;
3. RUNTIME:在运行时有效;
Retention meta-annotation类型有唯一的value作为成员,它的取值来自于java.lang.annotation.RetentionPolicy的枚举值类型。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
public String columnName() default "column";
}

Column注解的RetentionPolicy的属性值时RUNTIME,这样注解处理器通过发射机制获取到该注解的属性值,从而做一些运行时的逻辑处理。

@Documented
@Documented用于描述其他类型的Annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc等此类工具文档化。@Documented是一个标记注解,没有成员。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Row {
public boolean defaultRowValue default false;
}		

@Inherited
@Inherited元注解是一个标记注解,@Inherited表明某个被注解的类型是被继承的,若干一个使用了@Inherited修饰的Annotation类型的class类,这这个Annotation将被用于该class的子类。
当@Inherited Annotation类型标注的Annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited Annotation类型标注的Annotation时,反射代码检查将开展工作:检查class和其父类,直到发现指定的Annotation类型,或者达到继承结构的顶层。

@Inherited
public @interface ArrayClass {
public enum Type{ COLUMN, ROW }
Type type() default Type.ROW;
}

二. 自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中每一个方法实际上是声明了一个配置参数,方法的名称就是参数名称,返回值类型就是参数类型,可以通过default来声明参数的默认值。
自定义注解的格式:
public @interface 注解名称 {定义体}
注解参数支持的数据类型:
1. 所有基本数据类型(int, float, boolean, byte, double, char, long, short)
2. String类型;
3. Enum类型;
4. Annotation类型;
5. Class类型;
6. 以及以上所有类型的数组;
Annotation注解定义体里面参数设定要求:
1. 只能用public或者默认(default)这两个访问权限修饰;
2. 参数成员只能用以上的类型;
3. 如果只有一个参数成员,最好把参数名设为"value",后面跟上小括号;
自定义注解示例:

import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Person {
		String value() default "";
}

注解元素的默认值:
注解元素必须要有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,因此使用空字符串或者0,-1是一种常用的做法。
三. 自定义注解实践:
注意:
定义了注解并在需要的时候给相关的类,雷属性上加注解信息,如果没有响应注解信息处理流程,注解则没有发挥作用,所有注解的处理方法就显得很重要。

**自定义一个注解MyAnnotation**

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	String param1() default "hello";
	String param2();
}
**使用自定义注解类MyAnnotation:**

public class MyAnnotationTest {
	@MyAnnotation(param1 = "Hello", param2 = "World")
	public void show () {
		System.out.println("MyAnnotationTest is running !");
}
**利用反射机制来响应被注解的内容**
// 此用例使用的spring框架

import java.lang.reflect.Method;
import org.springframework.beans.BeanException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.steretype.Component;

@Component
public class MyReflection implements BeanPostProcessor  {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String s) throws BeansException {
			return bean;
	}
@Override
public Object postProcessAfterInitialization(Object bean, String s) throws BeansExcepiton {
		if (bean.getClass().isAnnotationPresent(MyAnnotation.class)) {
				Method[] methods = bean.getClass().getMethods();
				for (Method method : methods) {
						Class paramType = method.getParameterType()[0];
						try {
								method.invoke(bean, paramType);
						} catch (Exception e) {
								e.printStackTrace();
						}
				}
		}
		return bean;
}
发布了12 篇原创文章 · 获赞 19 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/u012675150/article/details/86683089