我学技术一直抱着“知其然,知其所以然”的态度,如果学一个技术只停留在会用的表面上是满足不了我的,我会找出它的底层实现之后,才不会有所遗憾。而要找出它的底层实现的办法就是看它的源码,有一句话说:“源码面前了无秘密”。就这样,我阅读了一些Java API和一些开源框架的源码:Java集合框架源码、Spring源码、Struts2源码、JDK动态代理源码,从中学到了不少的东西。对于
反射机制和JDK动态代理的用法和实现原理都已经非常的熟悉。
虽然在这之前已经对
Annotation的用法已经非常的熟悉,但是一直不知道它的底层是怎么实现的。最近两天在看Spring MVC的源码,在那大量的使用了Annotation,这让我有了一个想法:这Annotation这么神奇,它的底层是怎么实现的呢?
就带着这样的一个问号,自己写了一个小小的测试程序。
package annotation.principle;
import org.junit.Test;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Annotation测试
* @author zyb
* @since 2012-8-9
*/
@RequestMapping("test")
public class AnntotationTest {
@Test
public void testAnnotion() {
RequestMapping requestMapping = AnntotationTest.class.getAnnotation(RequestMapping.class);
System.out.println(requestMapping.getClass().getName());
}
}
打印出来的结果让我吃了一惊,这不就是动态代理嘛。
到了这里之后,带着这样的疑问,在Google和百度上搜了一下“
注解的底层实现”,看到的都是教你怎么用注解的,我吐血。翻了一下《深入
理解Java虚拟机》也没有找到答案,算了,自己动手。
为了证实注解的实现是用了动态代理,自己又写了另外一段代码来验证自己的想法。
package annotation;
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 RequestMapping {
String value();
}
package annotation;
public class User {
@RequestMapping("name")
public String add(String name) {
return "add";
}
}
package annotation;
import java.lang.reflect.Method;
/**
* 注解工具类
* @author zyb
* @since 2012-8-9
*/
public class AnnotationUtils {
/**
* 打印注解信息
*/
public static void printAnnotationInfo() throws Exception {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Method[] methods = User.class.getDeclaredMethods();
for (Method method : methods) {
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
System.out.println("Methods from super class:");
for (Method annotationMethod : requestMapping.getClass().getMethods()) {
System.out.println(annotationMethod.getName());
}
System.out.println("----------------------------------");
System.out.println("super class:" + requestMapping.getClass().getSuperclass().getName());
System.out.print("super interfaces:");
for (Class interfaceClass : requestMapping.getClass().getInterfaces()) {
System.out.println(interfaceClass.getName());
}
System.out.println("----------------------------------");
System.out.println("InvocationHandler:" + requestMapping.getClass());
// System.out.println(requestMapping.getClass().getMethod("getProxyClass", ClassLoader.class,
// RequestMapping.class).
// invoke(requestMapping,
// Thread.currentThread().getContextClassLoader(), RequestMapping.class));
}
}
/**
* 把产生代理类的class文件保存到硬盘上
*/
public static void saveProxyClassInHardDisk() {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
}
}
package annotation;
/**
* 注解测试
* @author zyb
* @since 2012-8-9
*/
public class AnnotationTest {
public static void main(String[] args) throws Exception {
// 生成代理类class文件的代码一定在放在main方法,用JUnit生成不了
AnnotationUtils.saveProxyClassInHardDisk();
AnnotationUtils.printAnnotationInfo();
}
}
打印的结果如下:
Java HotSpot(TM) Client VMwarning: increase O_BUFLEN in ostream.hpp -- output truncated
Methods from super class:
value
hashCode
equals
toString
annotationType
isProxyClass
newProxyInstance
getInvocationHandler
getProxyClass
wait
wait
wait
getClass
notify
notifyAll
----------------------------------
superclass:java.lang.reflect.Proxy
super interfaces:annotation.RequestMapping
一看结果,我的想法果然是对的。Java为这个RequestMapping注解生成了一个代理类,名字叫$Proxy3,这个$Proxy3的父类是Proxy,实现的
接口是RequestMapping,原来RequestMapping注解是一个接口,这个接口继承自Annotation接口,所以打印出了Annotation接口中的所有方法。
再来看一下自动生成的那个代理类是长
什么样子的,
// Decompiled by DJ v3.11.11.95 Copyright 2009 Atanas Neshkov Date: 2012/8/9 14:39:44
// Home Page: http://members.fortunecity.com/neshkov/dj.html http://www.neshkov.com/dj.html - Check often for new version!
// Decompiler options: packimports(3)
import annotation.RequestMapping;
import java.lang.reflect.*;
public final class $Proxy3 extends Proxy
implements RequestMapping
{
public $Proxy3(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String value()
{
try
{
return (String)super.h.invoke(this, m3, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final Class annotationType()
{
try
{
return (Class)super.h.invoke(this, m4, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m4;
private static Method m2;
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m3 = Class.forName("annotation.RequestMapping").getMethod("value", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m4 = Class.forName("annotation.RequestMapping").getMethod("annotationType", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
看到这代码之后,基本上明白注解的底层是怎么实现的了。但是,我还有一点东西没有揪出来,那就是:这个注解的实现类是谁(也就是目标对象)?InvocationHandler的实现类是谁?
如果这两个东西揪出来之后,就可以知道,在调用目标对象方法之前做了什么,调用方法之后又做了什么,这才是关键所在。。。。。
谢谢jilen的提示,现在这两东西已经找出来了,首先是生成代理对象的地方,在AnnotationParser类中的annotationForMap方法中。
public static Annotation annotationForMap(
Class<? extends Annotation> type, Map<String, Object> memberValues)
{
return (Annotation) Proxy.newProxyInstance(
type.getClassLoader(), new Class[] { type },
new AnnotationInvocationHandler(type, memberValues));
}
再看一下AnnotationInvocationHandler的实现
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
private final Class<? extends Annotation> type;
private final Map<String, Object> memberValues;
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
this.type = type;
this.memberValues = memberValues;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
assert paramTypes.length == 0;
if (member.equals("toString"))
return toStringImpl();
if (member.equals("hashCode"))
return hashCodeImpl();
if (member.equals("annotationType"))
return type;
// Handle annotation member accessors
Object result = memberValues.get(member);
if (result == null)
throw new IncompleteAnnotationException(type, member);
if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();
if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);
return result;
}
// 省略其他方法的代码
}