java注解

一.定义

​ 注解(annotation)也叫元数据,可以在指定位置标记可以在编译、类加载、运行时被读取,然后进行相应的处理。


二.常见的注解

1.@Override

​ 当子类重写父类方法时,子类的该方法可以加入此注解。作用:确保子类确实重写了父类方法,且在父类删除该方法时,在子类中该错误会有错误提示。


2.@Deprecated

​ 该注解作用于方法和类上,标记改元素已过期,用户使用该方法或类时,编译器可以做出相应的警告,告诉用户不推荐使用。


3.@Suppvisewarnings

​ 用于通知java编译器禁止特定的编译警告。


三.注解的好处

​ 1.现在的常用框架、工具等都广泛的应用了注解,使用时能够读懂别人的代码。

​ 2.在不影响业务逻辑的情况下,与业务代码进行分离。

​ 3.代替繁琐的xml配置


四.元注解

元注解是可以注解到其它注解上的注解,由jdk提供的一种最基本的注解。


1.@Retention

​ Retention的英文意思是保留期。该注解标记了被注解的注解的生命周期。

​ 该注解的值有:

  • RetentionPolicy.SOURCE 该注解只在源代码上保留,在编译器编译时将会被忽略,更无法加载到JVM中,在运行时程序无法获取该注解的元信息。
  • RetentionPolicy.CLASS 该注解在编译器保留,但无法加载到JVM中,在运行时无法获取到该注解的元信息。
  • RetentionPolicy.RUNTIME 该注解在运行时保留,加载到JVM中,在运行时可以获取到该注解的元信息。

2.@Documented

​ 该注解与文档相关,它的作用是能够将注解中的元信息包含到javadoc中。


3.@Target

​ Target的英文意思是目标。该注解标记了注解运用的地方

​ 该注解的值有:

  • ElementType.ANNOTATION_TYPE 可以对一个注解进行注解。
  • ElementType.CONSTRUCTOR 可以对构造方法进行注解。
  • ElementType.FIELD 可以给属性进行注解。
  • ElementType.LOCAL_VARIABLE 可以对局部变量进行注解。
  • ElementType.METHOD 可以对方法进行注解。
  • ElementType.PACKAGE 可以对包进行注解。
  • ElementType.PARAMETER 可以对方法的参数进行注解。
  • ElementType.TYPE 可以对类型进行注解,比如类、接口、枚举。

4.@Inherited

Inherited的英文意思是继承。它的作用是如果一个超[email protected],如果子类没有被任何注解注解的话,那么子类继承超类的注解。

5.@Repeatable

​ Repeatable的英文意思是可重复的。它的作用的在同一个目标上能够应用多次。


五.注解的属性

​ 注解的属性也叫注解的成员变量。需要注意的是,在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。

注解中属性可以有默认值,默认值需要用 default 关键值指定。

​ 代码示例:

1
2
3
4
5
6
(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
public @interface TestAnnotation {
DataSource () default DataSource.MASTER;
String myValue() default "default";
}

六.提取注解

###1.注解通过反射获取。

​ 首先可以通过Class对象的isAnnotation()方法判断它是否应用了某个注解,方法原型:

1
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);

​ 然后通过getAnnotation()获取Annotation对象,方法原型:

1
public <A extends Annotation> A getAnnotation(Class<A> annotationClass);

​ 当然,可以通过getAnnotations() 获取注解列表,方法原型:

1
public Annotation[] getAnnotations();

2.获取元数据

​ 获取到Annotation对象后,通过对应的方法获取值,示例代码(对应以上TestAnnotion):

1
2
3
4
if (Main.class.isAnnotationPresent(TestAnnotation.class)){
TestAnnotation annotation = Main.class.getAnnotation(TestAnnotation.class);
System.out.println(annotation.value());
}

七.示例

1.目的

​ 使用注解给方法标记,通过注解获取数据源。

2.编写主从数据库主从枚举类

1
2
3
4
5
6
7
8
9
10
11
public enum DataSourceType {

* 主库
*/
MASTER,


* 从库
*/
SLAVE
}

3.自定义一个注解TestAnnotation

1
2
3
4
5
(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSource {
DataSourceType () default DataSourceType.MASTER;
}

4.数据库查询类

1
2
3
4
5
6
public UserDbHelper{
@DataSource(DataSourceType.SLAVE)
User selectByPrimaryKey(Integer id){
//查询数据库代码
}
}

5.主类

1
2
3
4
5
6
7
8
public class Main{
public static void main(String[] args){
if(UserDbHelper.class.isAnnotationPresent(DataSource.class)){
Annotation annotation = UserDbHelper.class.getAnnotation(DataSource.class);
System.out.println(annotation.value());
}
}
}

最终程序输出:SLAVE

八.后记

​ 在示例代码中,只是获取到标记的内容并输出,并没有达到动态切换数据源的目的。如果需要,则需要使用aop在selectByPrimaryKey方法设置切点,在调用该方法前,在切面中,通过注解获取该方法的DataSource注解,通过该注解获取标记DataSourceType,然后切换数据源为DataSourceType对应的据源,来达到动态数据源的目的。在该方法执行完后,再切换为MASTER数据源。