免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1077 | 回复: 0
打印 上一主题 下一主题

用ASM直接读取字节码来加载Class的Annotation [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-06-11 21:50 |只看该作者 |倒序浏览
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 ListAnnotationNode> visibleAnnotations;
16

17

    public ListAnnotationNode> 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 ArrayListAnnotationNode> (1);
28

            }
29

            visibleAnnotations.add(an);
30


        } else

{
31


            if (invisibleAnnotations == null)

{
32

                invisibleAnnotations = new ArrayListAnnotationNode> (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 ListAnnotationNode> getVisibleAnnotations()

{
63

        return visibleAnnotations;
64

    }
65

66


    public ListAnnotationNode> 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.util.Enumeration;
8

import java.util.HashSet;
9

import java.util.Iterator;
10

import java.util.List;
11

import java.util.Set;
12

import java.util.zip.ZipEntry;
13

import java.util.zip.ZipException;
14

import java.util.zip.ZipFile;
15

16

import org.objectweb.asm.ClassReader;
17

import org.objectweb.asm.Type;
18

import org.objectweb.asm.tree.AnnotationNode;
19

20


public class ClassParser

{
21

    @SuppressWarnings("unchecked")
22


    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, URISyntaxException

{
23

        EnumerationURL> urls = getClassLoader().getResources(".");
24

        SetString> result = new HashSetString>();
25


        while(urls.hasMoreElements())

{
26

            URL url = urls.nextElement();
27

            File file = new File(url.toURI());
28


            if (file.isDirectory())

{
29

                handleDirectory(result, file, null);
30


            } else

{
31

                handleArchive(result, file);
32

            }
33

        }
34

        
35


        for(String clsRsName : result)

{
36

            ClassVisitorFaker cv = new ClassVisitorFaker();
37

            ClassReader cr = new ClassReader(getClassLoader().getResourceAsStream(clsRsName));
38

            cr.accept(cv, 0);
39

            ListAnnotationNode> annotationsList = cv.getVisibleAnnotations();
40


            if(null != annotationsList)

{
41


                for(IteratorAnnotationNode> it = annotationsList.iterator(); it.hasNext();)

{
42

                    AnnotationNode annotation = it.next();
43

                    Type t = Type.getType(annotation.desc);
44


                    if(AnnotationFaker.class.getName().equals(t.getClassName()))

{
45

                        Class clazz = Class.forName(filenameToClassname(clsRsName));
46

                        ClassFaker faker = (ClassFaker) clazz.newInstance();
47

                        faker.hello();
48

                    }
49

                }
50

            }
51

         
52

        }
53

     
54

    }
55

   
56


    private static void handleDirectory(final SetString> result, final File file, final String path)

{
57


        for (final File child : file.listFiles())

{
58

            final String newPath = path == null ? child.getName() : path + '/' + child.getName();
59


            if (child.isDirectory())

{
60

                handleDirectory(result, child, newPath);
61


            } else

{
62

                handleItem(result, newPath);
63

            }
64

        }
65

    }
66

   
67


    private static void handleItem(final SetString> result, final String name)

{
68


        if (name.endsWith(".class"))

{
69

            result.add(name);
70

        }
71

    }
72

   
73


    private static void handleArchive(final SetString> result, final File file) throws ZipException, IOException

{
74

        final ZipFile zip = new ZipFile(file);
75

        final Enumeration extends ZipEntry> entries = zip.entries();
76


        while (entries.hasMoreElements())

{
77

            final ZipEntry entry = entries.nextElement();
78

            final String name = entry.getName();
79

            handleItem(result, name);
80

        }
81

    }
82

   
83


    private static ClassLoader getClassLoader()

{
84

        ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
85


        if(clsLoader == null)

{
86

            clsLoader = ClassLoader.getSystemClassLoader();
87

        }
88

        return clsLoader;
89

    }
90

   
91

   
92


    public static String filenameToClassname(final String filename)

{
93

        return filename.substring(0, filename.lastIndexOf(".class")).replace('/', '.').replace('\\', '.');
94

    }
95

   
96

97

}

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/19897/showart_971888.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP