📄 _chapter 9.htm
字号:
<table cellSpacing="0" cellPadding="1" width="90%" border="0">
<tr>
<td vAlign="top" width="60">
<img alt="graphics/note.gif" src="note.gif" align="left" border="0" width="54" height="53"><br>
</td>
<td vAlign="top">
<p class="docText">This technique has other uses as well, such as "hot
deployment" of servlets and Enterprise Java Beans. See
<a class="docLink" href="http://developer.java.sun.com/developer/techtips/2000/tt1027.html" target="_blank">
http://developer.java.sun.com/developer/TechTips/2000/tt1027.html</a> for
more information.</td>
</tr>
</table>
</div>
<h4 class="docSection2Title" id="ch09lev2sec1">Writing Your Own Class Loader</h4>
<p class="docText">To write your own class loader, you simply extend the <tt>
ClassLoader</tt> class and override the method.</p>
<pre>findClass(String className)
</pre>
<p class="docText">The <tt>loadClass</tt> method of the <tt>ClassLoader</tt>
superclass takes care of the delegation to the parent and only calls <tt>
findClass</tt> if the class hasn't already been loaded and if the parent class
loader was unable to load the class.</p>
<div class="docNote">
<p class="docNoteTitle">NOTE</p>
<table cellSpacing="0" cellPadding="1" width="90%" border="0">
<tr>
<td vAlign="top" width="60">
<img alt="graphics/note.gif" src="note.gif" align="left" border="0" width="54" height="53"><br>
</td>
<td vAlign="top">
<p class="docText">In earlier versions of the SDK, programmers had to
override the <tt>loadClass</tt> method. That is no longer recommended.</td>
</tr>
</table>
</div>
<p class="docText">Your implementation of this method must:</p>
<ol class="docList">
<span style="font-weight: bold" TYPE="1">
<li><span style="font-weight: normal">
<p class="docList">Load the bytecodes for the class from the local file system
or from some other source.</span></li>
<li><span style="font-weight: normal">
<p class="docList">Call the <tt>defineClass</tt> method of the <tt>ClassLoader</tt>
superclass to present the bytecodes to the virtual machine.</span></span></li>
</ol>
<p class="docText">In the program of <a class="docLink" href="#ch09list01">
Example 9-1</a>, we implement a class loader that loads encrypted class files.
The program asks the user for the name of the first class to load (that is, the
class containing <tt>main</tt>) and the decryption key. It then uses a special
class loader to load the specified class and calls the <tt>main</tt> method. The
class loader decrypts the specified class and all nonsystem classes that are
referenced by it. Finally, the program calls the <tt>main</tt> method of the
loaded class (see <a class="docLink" href="#ch09fig01">Figure 9-1</a>).</p>
<center>
<h5 id="ch09fig01" class="docFigureTitle">Figure 9-1. The <tt>ClassLoaderTest</tt> program</h5>
<p>
<img alt="graphics/09fig01.gif" src="09fig01.gif" border="0" width="403" height="341"><br>
</p>
</center>
<p class="docText">For simplicity, we ignore 2,000 years of progress in the
field of cryptography and use the venerable Caesar cipher for encrypting the
class files.</p>
<div class="docNote">
<p class="docNoteTitle">NOTE</p>
<table cellSpacing="0" cellPadding="1" width="90%" border="0">
<tr>
<td vAlign="top" width="60">
<img alt="graphics/note.gif" src="note.gif" align="left" border="0" width="54" height="53"><br>
</td>
<td vAlign="top">
<p class="docText">David Kahn's wonderful book <i>The Codebreakers</i>
[Macmillan, NY, 1967, p. 84] refers to Suetonius as a historical source
for the Caesar cipher. Caesar shifted the 24 letters of the Roman alphabet
by 3 letters. At the time of this writing, the U.S. government restricts
the export of strong encryption methods. Therefore, we use Caesar's method
for our example since it is so weak that it is presumably legal for
export.</td>
</tr>
</table>
</div>
<p class="docText">Our version of the Caesar cipher has as a key a number
between 1 and 255. To decrypt, simply add that key to every byte and reduce
modulo 256. The <tt>Caesar.java</tt> program of
<a class="docLink" href="#ch09list02">Example 9-2</a> carries out the
encryption.</p>
<p class="docText">In order not to confuse the regular class loader, we use a
different extension, <tt>.caesar</tt>, for the encrypted class files.</p>
<p class="docText">To decrypt, the class loader simply subtracts the key from
every byte. On the CD-ROM for this book, you will find four class files,
encrypted with a key value of 3梩he traditional choice. You cannot load these
classes via the regular bytecode interpreter, but you can run the encrypted
program by using the custom class loader defined in our <tt>ClassLoaderTest</tt>
program.</p>
<p class="docText">Encrypting class files has a number of practical uses
(provided, of course, that you use a cipher stronger than the Caesar cipher).
Without the decryption key, the class files are useless. They can neither be
executed by a standard bytecode interpreter nor readily disassembled.</p>
<p class="docText">This means that you can use a custom class loader to
authenticate the user of the class or to ensure that a program has been paid for
before it will be allowed to run. Of course, encryption is only one application
of a custom class loader. You can use other types of class loaders to solve
other problems, for example, storing class files in a database.</p>
<h5 id="ch09list01" class="docExampleTitle">Example 9-1 ClassLoaderTest.java</h5>
<pre> 1. import java.util.*;
2. import java.io.*;
3. import java.lang.reflect.*;
4. import java.awt.*;
5. import java.awt.event.*;
6. import javax.swing.*;
7.
8. /**
9. This program demonstrates a custom class loader that decrypts
10. class files.
11. */
12. public class ClassLoaderTest
13. {
14. public static void main(String[] args)
15. {
16. JFrame frame = new ClassLoaderFrame();
17. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
18. frame.show();
19. }
20. }
21.
22. /**
23. This frame contains two text fields for the name of the class
24. to load and the decryption key.
25. */
26. class ClassLoaderFrame extends JFrame
27. {
28. public ClassLoaderFrame()
29. {
30 setTitle("ClassLoaderTest");
31. setSize(WIDTH, HEIGHT);
32. getContentPane().setLayout(new GridBagLayout());
33. GridBagConstraints gbc = new GridBagConstraints();
34. gbc.weightx = 0;
35. gbc.weighty = 100;
36. gbc.fill = GridBagConstraints.NONE;
37. gbc.anchor = GridBagConstraints.EAST;
38. add(new JLabel("Class"), gbc, 0, 0, 1, 1);
39. add(new JLabel("Key"), gbc, 0, 1, 1, 1);
40. gbc.weightx = 100;
41. gbc.fill = GridBagConstraints.HORIZONTAL;
42. gbc.anchor = GridBagConstraints.WEST;
43. add(nameField, gbc, 1, 0, 1, 1);
44. add(keyField, gbc, 1, 1, 1, 1);
45. gbc.fill = GridBagConstraints.NONE;
46. gbc.anchor = GridBagConstraints.CENTER;
47. JButton loadButton = new JButton("Load");
48. add(loadButton, gbc, 0, 2, 2, 1);
49. loadButton.addActionListener(new
50. ActionListener()
51. {
52. public void actionPerformed(ActionEvent event)
53. {
54. runClass(nameField.getText(), keyField.getText());
55. }
56. });
57. }
58.
59. /**
60. A convenience method to add a component to given grid bag
61. layout locations.
62. @param c the component to add
63. @param gbc the grid bag constraints to use
64. @param x the x grid position
65. @param y the y grid position
66. @param w the grid width
67. @param h the grid height
68. */
69. public void add(Component c, GridBagConstraints gbc,
70. int x, int y, int w, int h)
71. {
72. gbc.gridx = x;
73. gbc.gridy = y;
74. gbc.gridwidth = w;
75. gbc.gridheight = h;
76. getContentPane().add(c, gbc);
77. }
78.
79. /**
80. Runs the main method of a given class.
81. @param name the class name
82. @param key the decryption key for the class files
83. */
84. public void runClass(String name, String key)
85. {
86. try
87. {
88. ClassLoader loader
89. = new CryptoClassLoader(Integer.parseInt(key));
90. Class c = loader.loadClass(name);
91. String[] args = new String[] {};
92.
93. Method m = c.getMethod("main",
94. new Class[] { args.getClass() });
95. m.invoke(null, new Object[] { args });
96. }
97. catch (Throwable e)
98. {
99. JOptionPane.showMessageDialog(this, e);
100. }
101. }
102.
103. private JTextField keyField = new JTextField("3", 4);
104. private JTextField nameField = new JTextField(30);
105. private static final int WIDTH = 300;
106. private static final int HEIGHT = 200;
107. }
108.
109. /**
110. This class loader loads encrypted class files.
111. */
112. class CryptoClassLoader extends ClassLoader
113. {
114. /**
115. Constructs a crypto class loader.
116. @param k the decryption key
117. */
118. public CryptoClassLoader(int k)
119. {
120. key = k;
121. }
122.
123. protected Class findClass(String name)
124. throws ClassNotFoundException
125. {
126. byte[] classBytes = null;
127. try
128. {
129. classBytes = loadClassBytes(name);
130. }
131. catch (IOException exception)
132. {
133. throw new ClassNotFoundException(name);
134. }
135.
136. Class cl = defineClass(name, classBytes,
137. 0, classBytes.length);
138. if (cl == null)
139. throw new ClassNotFoundException(name);
140. return cl;
141. }
142.
143. /**
144. Loads and decrypt the class file bytes.
145. @param name the class name
146. @return an array with the class file bytes
147. */
148. private byte[] loadClassBytes(String name)
149. throws IOException
150. {
151. String cname = name.replace('.', '/') + ".caesar";
152. FileInputStream in = null;
153. try
154. {
155. in = new FileInputStream(cname);
156. ByteArrayOutputStream buffer
157. = new ByteArrayOutputStream();
158. int ch;
159. while ((ch = in.read()) != -1)
160. {
161. byte b = (byte)(ch - key);
162. buffer.write(b);
163. }
164. in.close();
165. return buffer.toByteArray();
166. }
167. finally
168. {
169. if (in != null)
170. in.close();
171. }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -