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
2.ClassFaker: 被AnnotationFaker標注的class
3.ClassVisitorFaker:ClassVisitor的一個實現,用來得到class上的Annotation
4.ClassParser: main class, 分析classpath上的class,如果是用AnnotationFaker標注的class,我們就初始化它。
舉一個例子吧,我們用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

3

4

5

6

7

8

9

10

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

2

3

4

5

6

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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

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
}
125

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

posted on 2008-06-11 17:38 叱咤紅人 閱讀(2943) 評論(0) 編輯 收藏 所屬分類: J2SE and JVM 、Other Java and J2EE frameworks