用ASM直接读取字节码来加载Class的Annotation

Asm是很好的ByteCode generator 和 ByteCode reader。Asm提供了ClassVisitor来访问Class中的每个元素。当用ClassReader来读取Class的字节码时,每read一个元素,ASM会调用指定的ClassVisitor来访问这个元素。这就是访问者模式。利用这个特点,当ClassVisitor访问Class的Annotation元素时,我们会把annotation的信息记录下来。这样就可以在将来使用这个Annotation。
举一个例子吧,我们用AnnotationFaker来标注一个Class,也就是Annotation的target是Type级别。当我们发现某个class是用AnnotationFaker标注的,我们就load这个class到jvm中,并初始化,否则免谈。

1.AnnotationFaker: annnotation用来标注需要初始化的class
 1 package  com.oocl.isdc.sha.frm.test.config;
 2
 3 import  java.lang.annotation.ElementType;
 4 import  java.lang.annotation.Retention;
 5 import  java.lang.annotation.RetentionPolicy;
 6 import  java.lang.annotation.Target;
 7
 8   @Retention(RetentionPolicy.RUNTIME)
 9   @Target( {ElementType.TYPE} )
10   public  @ interface  AnnotationFaker  {
11  }

12

2.ClassFaker: 被AnnotationFaker标注的class

1 package  com.oocl.isdc.sha.frm.test.config;
2
3 @AnnotationFaker
4    public   class  ClassFaker  {
5      public void hello() {
6       System.out.println("hello world, load me success!");
7      }

8  }

9


3. ClassVisitorFaker:ClassVisitor的一个实现,用来得到class上的Annotation

 1 package  com.oocl.isdc.sha.frm.test.config;
 2
 3 import  java.util.ArrayList;
 4 import  java.util.List;
 5
 6 import  org.objectweb.asm.AnnotationVisitor;
 7 import  org.objectweb.asm.Attribute;
 8 import  org.objectweb.asm.ClassVisitor;
 9 import  org.objectweb.asm.FieldVisitor;
10 import  org.objectweb.asm.MethodVisitor;
11 import  org.objectweb.asm.tree.AnnotationNode;
12
13 public   class  ClassVisitorFaker  implements  ClassVisitor {
14
15    public List<AnnotationNode> visibleAnnotations;
16
17    public List<AnnotationNode> invisibleAnnotations;
18    
19      public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
20      
21    }

22
23    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
24        AnnotationNode an = new AnnotationNode(desc);
25        if (visible) {
26            if (visibleAnnotations == null{
27                visibleAnnotations = new ArrayList<AnnotationNode> (1);
28            }

29            visibleAnnotations.add(an);
30        }
 else {
31            if (invisibleAnnotations == null{
32                invisibleAnnotations = new ArrayList<AnnotationNode> (1);
33            }

34            invisibleAnnotations.add(an);
35        }

36        return an;
37    }

38
39    public void visitAttribute(Attribute attr) {
40    }

41
42    public void visitEnd() {
43    }

44
45    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
46        return null;
47    }

48
49    public void visitInnerClass(String name, String outerName, String innerName, int access) {
50    }

51
52    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
53        return null;
54    }

55
56    public void visitOuterClass(String owner, String name, String desc) {
57    }

58
59    public void visitSource(String source, String debug) {
60    }

61
62    public List<AnnotationNode> getVisibleAnnotations() {
63        return visibleAnnotations;
64    }

65
66    public List<AnnotationNode> getInvisibleAnnotations() {
67        return invisibleAnnotations;
68    }

69}

70


4. ClassParser: main class, 分析classpath上的class,如果是用AnnotationFaker标注的class,我们就初始化它。

  1 package  com.oocl.isdc.sha.frm.test.config;
  2
  3 import  java.io.File;
  4 import  java.io.IOException;
  5 import  java.net.URISyntaxException;
  6 import  java.net.URL;
  7 import  java.net.URLClassLoader;
  8 import  java.net.URLDecoder;
  9 import  java.util.Enumeration;
 10 import  java.util.HashSet;
 11 import  java.util.Iterator;
 12 import  java.util.List;
 13 import  java.util.Set;
 14 import  java.util.zip.ZipEntry;
 15 import  java.util.zip.ZipException;
 16 import  java.util.zip.ZipFile;
 17
 18 import  org.objectweb.asm.ClassReader;
 19 import  org.objectweb.asm.Type;
 20 import  org.objectweb.asm.tree.AnnotationNode;
 21
 22 public   class  ClassParser  {
 23    @SuppressWarnings("unchecked")
 24    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException,
 25            IllegalAccessException, URISyntaxException {
 26        Set<String> result = new HashSet<String>();
 27
 28        if (getClassLoader() instanceof URLClassLoader) {
 29            URL[] urls = ((URLClassLoader) getClassLoader()).getURLs();
 30            for (URL u : urls) {
 31                File file = new File(u.toURI());
 32                if (file.isDirectory()) {
 33                    handleDirectory(result, file, null);
 34                }
 else if (file.getName().toLowerCase().endsWith(".jar")) {
 35                    handleArchive(result, file);
 36                }

 37            }

 38        }
else{
 39            Enumeration<URL> urls = getClassLoader().getResources(".");
 40            while (urls.hasMoreElements()) {
 41                String urlPath = urls.nextElement().getFile();
 42                // System.out.println(urlPath);
 43                urlPath = URLDecoder.decode(urlPath, "UTF-8");
 44                if (urlPath.startsWith("file:")) {
 45                    urlPath = urlPath.substring(5);
 46                }

 47                if (urlPath.indexOf('!'> 0{
 48                    urlPath = urlPath.substring(0, urlPath.indexOf('!'));
 49                }

 50
 51                final File file = new File(urlPath);
 52                if (file.isDirectory()) {
 53                    handleDirectory(result, file, null);
 54                }

 55
 56            }

 57        }

 58
 59     
 60
 61        for (String clsRsName : result) {
 62            ClassVisitorFaker cv = new ClassVisitorFaker();
 63            ClassReader cr = new ClassReader(getClassLoader().getResourceAsStream(clsRsName));
 64            cr.accept(cv, 0);
 65            List<AnnotationNode> annotationsList = cv.getVisibleAnnotations();
 66            if (null != annotationsList) {
 67                for (Iterator<AnnotationNode> it = annotationsList.iterator(); it.hasNext();) {
 68                    AnnotationNode annotation = it.next();
 69                    Type t = Type.getType(annotation.desc);
 70                    if (AnnotationFaker.class.getName().equals(t.getClassName())) {
 71                        Class clazz = Class.forName(filenameToClassname(clsRsName));
 72                        ClassFaker faker = (ClassFaker) clazz.newInstance();
 73                        faker.hello();
 74                    }

 75                }

 76            }

 77
 78        }

 79
 80    }

 81
 82    private static void handleDirectory(final Set<String> result, final File file, final String path)
 83            throws ZipException, IOException {
 84        for (final File child : file.listFiles()) {
 85            final String newPath = path == null ? child.getName() : path + '/' + child.getName();
 86            if (child.isDirectory()) {
 87                handleDirectory(result, child, newPath);
 88            }
 else if (child.getName().toLowerCase().endsWith(".jar")) {
 89                handleArchive(result, child);
 90            }
 else {
 91                handleItem(result, newPath);
 92            }

 93        }

 94    }

 95
 96    private static void handleItem(final Set<String> result, final String name) {
 97        if (name.endsWith(".class")) {
 98            result.add(name);
 99        }

100    }

101
102    private static void handleArchive(final Set<String> result, final File file) throws ZipException, IOException {
103        final ZipFile zip = new ZipFile(file);
104        final Enumeration extends ZipEntry> entries = zip.entries();
105        while (entries.hasMoreElements()) {
106            final ZipEntry entry = entries.nextElement();
107            final String name = entry.getName();
108            handleItem(result, name);
109        }

110    }

111
112    private static ClassLoader getClassLoader() {
113        ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
114        if (clsLoader == null{
115            clsLoader = ClassLoader.getSystemClassLoader();
116        }

117        return clsLoader;
118    }

119
120    public static String filenameToClassname(final String filename) {
121        return filename.substring(0, filename.lastIndexOf(".class")).replace('/''.').replace('\\''.');
122    }

123
124}

你可能感兴趣的:(ASM)