java-注解

探究java注解底层实现原理,首先自定义一个注解类

1
2
3
4
5
6
7
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyTypeAnnotation {
String name() default "";
}

再定义个main函数类来使用该注解

1
2
3
4
5
6
7
8
@MyTypeAnnotation(name="Test")
public class TestMyTypeAnnotation {
public static void main(String[] args) throws Exception {
MyTypeAnnotation type = TestMyTypeAnnotation.class.getAnnotation(MyTypeAnnotation.class);
System.out.println(type.name());
System.in.read(); //waiting...
}
}

运行javac *.java编译成class文件,通过javap查看字节码可知:注解是一种继承自接口java.lang.annotation.Annotation的特殊接口

1
2
3
4
5
[qiaojian@Mac testannotation ]% javap MyTypeAnnotation                                     [0]
Compiled from "MyTypeAnnotation.java"
public interface MyTypeAnnotation extends java.lang.annotation.Annotation {
public abstract java.lang.String name();
}

接口是怎么直接使用的呢?还是通过java中万能的动态代理实现的,动态代理会在运行时生成一个实现了MyTypeAnnotation接口的类实例,并设置上我们配置的注解属性值,然后通过反射获取。我们可以通过加上运行参数-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true生成动态代理类class文件

1
2
3
4
5
6
7
[qiaojian@Mac testannotation ]% java -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true TestMyTypeAnnotation
Test
^C% [qiaojian@Mac testannotation ]% ls [130]
MyTypeAnnotation.class TestMyTypeAnnotation.class com
MyTypeAnnotation.java TestMyTypeAnnotation.java
[qiaojian@Mac testannotation ]% ls com/sun/proxy/com/ [0]
\$Proxy0.class \$Proxy1.class com/

反编译查看class文件可知:生成的代理类实现了MyTypeAnnotation接口

1
2
3
4
5
6
7
8
9
10
11
[qiaojian@Mac proxy ]% javap \$Proxy1                                                      [0]
Warning: Binary file $Proxy1 contains com.sun.proxy.$Proxy1
public final class com.sun.proxy.$Proxy1 extends java.lang.reflect.Proxy implements MyTypeAnnotation {
public com.sun.proxy.$Proxy1(java.lang.reflect.InvocationHandler);
static {};
public final java.lang.String name();
public final boolean equals(java.lang.Object);
public final java.lang.String toString();
public final int hashCode();
public final java.lang.Class annotationType();
}

最后,我们可以通过HotSpot DeBuger工具来实时查看一下注解的实现和值是否和我们预期一样

首先,执行java,将程序跑起来

1
2
[qiaojian@Mac testannotation ]% java TestMyTypeAnnotation                                           [0]
Test

然后ps查看进程ID:88954

1
2
3
4
[qiaojian@Mac testannotation ]% psfind TestMyTypeAnnotation                                         [0]
PID TTY TIME CMD
88954 ttys001 0:00.21 /usr/bin/java TestMyTypeAnnotation
88965 ttys002 0:00.00 grep --color --color=auto TestMyTypeAnnotation

打开HSDB

1
2
[qiaojian@Mac testannotation ]% sudo java -cp /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/sa-jdi.jar sun.jvm.hotspot.HSDB
Password:

attach 进程ID

查看堆内存参数

查看注解的实现类实例

查看注解属性的设置值

使用HSDB可以方便的查看java 进程的运行时数据状态,方便debug

-------------本文结束感谢您的阅读-------------
Good for you!