[Prévia] [Próxima] [Prévia por assunto] [Próxima por assunto]
[Índice cronológico]
[Índice de assunto]
RE: Core Java Technologies Tech Tips, August, 19, 2003 (Formatting Messages, Unloading/Reloading Classes)
- Subject: RE: Core Java Technologies Tech Tips, August, 19, 2003 (Formatting Messages, Unloading/Reloading Classes)
- From: Fabio Kon <kon*ime:usp:br>
- Date: Tue, 19 Aug 2003 16:58:23 -0300
Veja que interessante. Será que agora isso já funciona realmente em Java?
[]s,
Fabio.
SDN - Core Java Technologies Tech Tips writes:
> Core Java Technologies Tech Tips
>
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> UNLOADING AND RELOADING CLASSES
>
> The July 22, 2003 Tech Tip titled "Compiling Source Directly From
> a Program" (http://bulkmail2.sun.com/CTServlet?id=40407956805922094:1061310102516)
> offered a way to compile source files directly from your Java
> program. It presented a simple editor in which you can name a
> class and provide the source. That approach works fine, provided
> the class is not one that you already compiled and loaded during
> the current execution run. If indeed you previously compiled and
> loaded the class, you can't then edit it and recompile it using
> the approach covered in the previous Tech Tip. The issue here is
> the underlying class loader. All classes loaded through the
> system class loader will never be unloaded. To allow the program
> to let you reedit the source for a class, and then recompile and
> reload it, you need to work with a different class loader. In
> this tip, you'll learn how to create a custom class loader, one
> that lets you load your newly compiled class (or any class).
> You'll also learn how to discard the class such that the next time
> you compile the class, the newly compiled class is loaded.
>
> An instance of the ClassLoader class of the java.lang package is
> responsible for loading all classes. For system classes, that
> class loader is available through the getSystemClassLoader method
> of ClassLoader. For user classes, if that class is already loaded,
> you can ask for the ClassLoader with the getClassLoader method of
> Class.
>
> In the RunIt program from the earlier Tech Tip, the forName
> method of Class was used to load the class data (that is, to get
> an instance of Class). If you want to use a different class
> loader, you have to use the loadClass method of ClassLoader to
> load the class data. In other words, you need to code this:
>
> String className = ...;
> Class aClass = loader.loadClass(className);
>
> instead of this:
>
> String className = ...;
> Class aClass = Class.forName(className);
>
> Functionally, the two code blocks above are identical when
> loading through the same class loader. The first block loads the
> class through the same loader as where the code is found. The
> second loads the class through the class loader specified by the
> loader variable. In both cases, you would then call something like
> newInstance to create an instance of the class.
>
> Repeated calls to Class.forName load the same class (assuming the
> class loader of the calling class doesn't change). Repeated calls
> to loader.loadClass load the same class. However, the second
> block allows you to reload a class. To do that, you create a new
> ClassLoader:
>
> String className = ...;
> // create new loader instance
> ClassLoader loader = ...;
> Class aClass = loader.loadClass(className);
>
> In this particular code block, a new loader is created between
> calls to loadClass. If the class definition for className changes
> between calls, the new version of the class is loaded the second
> time through.
>
> If you change the RunIt program to use this mechanism, you can
> edit the source after compiling and running the program. The
> program should generate output appropriate to the new source, not
> the old.
>
> The only thing left is where to get the ClassLoader. The
> ClassLoader class is itself an abstract class. Predefined loaders
> include the SecureClassLoader of java.security, which adds
> permission support, and the URLClassLoader of java.net. Of the
> two predefined loaders, only URLClassLoader offers support for
> public construction through either its constructors or static
> newInstance methods. See the documentation for URLClassLoader
> (http://bulkmail2.sun.com/CTServlet?id=40407956805922094:1061310102531)
> for further details.
>
> Creating a URLClassLoader involves creating an array of URL
> objects. These URL objects serve as the locations that the custom
> class loader uses to find classes. You specify the elements of
> the array similarly to the way you specify path elements for the
> CLASSPATH environment variable, where the path elements are
> separated by a ; on Windows and a : on Unix machines. Each
> element in the URL array can be a located locally or on a remote
> host. Anything ending in a "/" is presumed to be a directory.
> Anything else is presumed to be a JAR file.
>
> For instance, if you want to create a ClassLoader that works like
> the default classpath, that is, only searching in the current
> directory, you can code the following:
>
> File file = new File(".");
> ClassLoader loader = new URLClassLoader(
> new URL[] {file.toURL()}
> );
>
> The first line creates a File object, referencing the current
> directory. The second line calls the URLClassLoader constructor.
> Passed into the constructor is an array of one URL object: the
> URL to the File.
>
> If you change the RunIt program to include the following code,
> recompile it, and run it, the program will discard the loaded
> classes between runs and reload them. Notice that unlike the
> RunIt program in the earlier Tech Tip, the following code does
> not create an instance of the class to invoke the main method.
> There is no need to create an instance of the class because the
> main method is static,
>
> // Create new class loader
> // with current dir as CLASSPATH
> File file = new File(".");
> ClassLoader loader = new URLClassLoader(
> new URL[] {file.toURL()}
> );
> // load class through new loader
> Class aClass = loader.loadClass(className.getText());
> // run it
> Object objectParameters[] = {new String[]{}};
> Class classParameters[] =
> {objectParameters[0].getClass()};
> Method theMethod = aClass.getDeclaredMethod(
> "main", classParameters);
> // Static method, no instance needed
> theMethod.invoke(null, objectParameters);
>
> Here's the complete code example, with the RunIt program renamed
> to RunItReload.
>
> import java.awt.*;
> import java.awt.event.*;
> import javax.swing.*;
> import java.io.*;
> import java.net.*;
> import java.lang.reflect.*;
>
> public class RunItReload extends JFrame {
> JPanel contentPane;
> JScrollPane jScrollPane1 = new JScrollPane();
> JTextArea source = new JTextArea();
> JPanel jPanel1 = new JPanel();
> JLabel classNameLabel = new JLabel("Class Name");
> GridLayout gridLayout1 = new GridLayout(2,1);
> JTextField className = new JTextField();
> JButton compile = new JButton("Go");
> Font boldFont = new java.awt.Font(
> "SansSerif", 1, 11);
>
> public RunItReload() {
> super("Editor");
> setDefaultCloseOperation(EXIT_ON_CLOSE);
> contentPane = (JPanel) this.getContentPane();
> this.setSize(400, 300);
> classNameLabel.setFont(boldFont);
> jPanel1.setLayout(gridLayout1);
> compile.setFont(boldFont);
> compile.setForeground(Color.black);
> compile.addActionListener(new ActionListener() {
> public void actionPerformed(ActionEvent e) {
> try {
> doCompile();
> } catch (Exception ex) {
> System.err.println(
> "Error during save/compile: " + ex);
> ex.printStackTrace();
> }
> }
> });
> contentPane.add(
> jScrollPane1, BorderLayout.CENTER);
> contentPane.add(jPanel1, BorderLayout.NORTH);
> jPanel1.add(classNameLabel);
> jPanel1.add(className);
> jScrollPane1.getViewport().add(source);
> contentPane.add(compile, BorderLayout.SOUTH);
> }
> public static void main(String[] args) {
> Frame frame = new RunItReload();
> // Center screen
> Dimension screenSize =
> Toolkit.getDefaultToolkit().getScreenSize();
> Dimension frameSize = frame.getSize();
> if (frameSize.height > screenSize.height) {
> frameSize.height = screenSize.height;
> }
> if (frameSize.width > screenSize.width) {
> frameSize.width = screenSize.width;
> }
> frame.setLocation(
> (screenSize.width - frameSize.width) / 2,
> (screenSize.height - frameSize.height) / 2);
> frame.show();
> }
> private void doCompile() throws Exception {
> // write source to file
> String sourceFile = className.getText() + ".java";
> FileWriter fw = new FileWriter(sourceFile);
> fw.write(source.getText());
> fw.close();
> // compile it
> int compileReturnCode =
> com.sun.tools.javac.Main.compile(
> new String[] {sourceFile});
> if (compileReturnCode == 0) {
> // Create new class loader
> // with current dir as CLASSPATH
> File file = new File(".");
> ClassLoader loader =
> new URLClassLoader(new URL[] {file.toURL()});
> // load class through new loader
> Class aClass = loader.loadClass(
> className.getText());
> // run it
> Object objectParameters[] = {new String[]{}};
> Class classParameters[] =
> {objectParameters[0].getClass()};
> Method theMethod = aClass.getDeclaredMethod(
> "main", classParameters);
> // Static method, no instance needed
> theMethod.invoke(null, objectParameters);
> }
> }
> }
>
> You need to compile and execute this program in a slightly
> different way than you did for the RunIt program in the earlier
> Tech Tip. Because the custom class loader is using the current
> directory as the place where reloadable classes need to come
> from, you can't load the actual RunItReload class from the same
> classpath. Otherwise, the system class loader will load the
> compiled class from the same location (and class loader). You
> need to tell the compiler to send the compiled classed for
> RunItReload to a different location. You run the program with
> that other location in the classpath, not with "." in it.
> Remember that you need to include tools.jar in the classpath to
> compile. The following command sends the newly compiled .class
> files for RunItReload to the XYZ subdirectory. Feel free to pick
> a different subdirectory name. (Although the command is shown on
> multiple lines it needs to go on one line):
>
> In Windows:
>
> mkdir XYZ
> javac -d XYZ -classpath
> c:\j2sdk1.4.2\lib\tools.jar RunItReload.java
>
> In Unix:
>
> mkdir XYZ
> javac -d XYZ -classpath
> /homedir/jdk14/j2sdk1.4.2/lib/tools.jar
> RunItReload.java
>
> Replace homedir with your actual home directory.
>
> If you get an error that the system cannot find the path
> specified, be sure to create the XYZ directory before compilation.
>
> As before, you need to include the tools.jar file in your runtime
> classpath, and you need to include the XYZ directory for the
> actual RunItReload program. To run the program, issue the
> following command. (Again, although the command is shown on
> multiple lines, it needs to go on one line).
>
> In Windows:
>
> java -classpath
> c:\j2sdk1.4.2\lib\tools.jar;XYZ RunItReload
>
> In Unix:
>
> java -classpath
> /homedir/jdk14/j2sdk1.4.2/lib/tools.jar:
> XYZ RunItReload
>
> The XYZ here is carried over from the prior javac step. The
> target directory for compilation (specified after -d) must match
> the runtime classpath.
>
> Running the program displays the GUI. Then you can:
>
> 1. Enter the name of the class, such as Sample2, to be compiled
> in the JTextField.
>
> 2. Enter the source code in the JTextArea. Here's the source code
> for Sample2:
>
> public class Sample2 {
> public static void main(String args[]) {
> System.out.println(new java.util.Date());
> // System.out.println("Hello, World!");
> }
> }
>
> 3. Click the Go button.
>
> Output is sent to the console. For example, Sample2 should
> produce output that looks something like this:
>
> Tue Aug 19 11:25:16 PDT 2003
>
> Comment out the line that prints the date, and uncomment the line
> that prints "Hello World". Click the Go button. You should now
> see the following in your console:
>
> Hello, World!
>
> You see a different line displayed because a new class loader was
> created, one that unloaded previously loaded classes.
>
> . . . . . . . . . . . . . . . . . . . . . . .
>
> IMPORTANT: Please read our Terms of Use, Privacy, and Licensing
> policies:
> http://www.sun.com/share/text/termsofuse.html
> http://www.sun.com/privacy/
> http://developer.java.sun.com/berkeley_license.html
>
> * FEEDBACK
> Comments? Please enter your feedback on the Tech Tips at:
>
> http://developers.sun.com/contact/feedback.jsp?category=sdn