- 论坛徽章:
- 0
|
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 |
|