深入理解Java加载类的机制.doc

上传人:rrsccc 文档编号:9861017 上传时间:2021-03-31 格式:DOC 页数:13 大小:72.50KB
返回 下载 相关 举报
深入理解Java加载类的机制.doc_第1页
第1页 / 共13页
深入理解Java加载类的机制.doc_第2页
第2页 / 共13页
深入理解Java加载类的机制.doc_第3页
第3页 / 共13页
深入理解Java加载类的机制.doc_第4页
第4页 / 共13页
深入理解Java加载类的机制.doc_第5页
第5页 / 共13页
点击查看更多>>
资源描述

《深入理解Java加载类的机制.doc》由会员分享,可在线阅读,更多相关《深入理解Java加载类的机制.doc(13页珍藏版)》请在三一文库上搜索。

1、深入理解Java加载类的机制这里从三个方面讲述java classloader1、翻译一下classloader的相关技术文章(来自Core Java第二卷的Chapter 9. Security),由于我的英文水平有限,难免有不合适,请大家指出。2、将从web应用出发模拟一下web应用的classloader(这节是重点)3、通过测试2实现的classloader来加深理解以下是翻译的关于ClassLoader介绍ClassLoaderJAVA编译器把源代码转换成一个假想机器(就是我们所说的虚拟机)的语言。虚拟机指令被保存在class后缀的文件里。每一个类文件包含类和接口的定义以及实现代码。

2、这些类文件必须被一个程序解释,这个程序能够把虚拟机的指令翻译成宿主机的机器语言。注意:虚拟机只加载执行一个程序所需要的类文件。举个例子,比如执行MyProgram.class,虚拟机运行的步骤如下:1、虚拟机有一个加载类文件的机制,比如,从硬盘读取文件或者就网络获得;虚拟机用这个机制加载MyProgram的类文件2、如果MyProgram有一个实例变量或者是超类,那么实例变量和超类的类文件也被加载。(加载一个类所依赖的所有类的过程叫做resolving the class-自己理解吧)3、然后虚拟机执行MyProgram的main方法(因为是静态方法,所以不需要new MyProgram的实例

3、)4、如果main 方法或者main方法调用的方法需要其他的类的话,这些类也被加载。类加载机制不是仅仅用一个类加载器,任何一个java程序至少有以下三个类加载器(为了不影响大家的理解,这里我就不翻译这三个类加载器的名称了)The bootstrap class loader:加载系统类(有代表性的,jdk的rt.jar里的类),他是虚拟机的必要组成部分,并且一般是用C实现的。也有类加载器对象(就是指具体的一个类加载器)不关联bootstrap class loader,比如String.class.getClassLoader()返回null.The extension class loade

4、r:加载jre/lib/ext目录下的class,你可以把你的jar文件放到这个目录,extension class loader将会加载到jar里面的类,即使你不设置classpath.(一些人建议使用这个机制以让你不受classpath的烦扰,不过注意以下的警告)The system class loader (有时也叫应用程序加载器):加载应用程序类。他主要加载classpath目录和jar/zip文件里的class,通过设置CLASSPATH环境变量或者是运行java的时候用 -classpath选项指定classpath在SUN的java实现里,the extension and s

5、ystem class loaders都是用java实现的,他们都是URLClassLoader类的实例。警告:如果你把jar文件放到jre/lib/ext目录下,并且你的jar文件中的类需要加载一个不是system or extension的类的话,你将遇到麻烦。扩展类加载器不使用类路径。如果你想把类放到jre/lib/ext下进行管理的话,请牢记这一点。=怎么理解这一点:也就是说如果你把自己的x.jar放到jre/lib/ext下的话,如果你自己的x.jar里的class要用到不在x.jar里也不在jre/lib/ext的类的话,会导致类加载不了。不难想象吧,因为你x.jar里的类是由ex

6、tension class loader加载的,他不会加载classpath路径下的类。警告:把jar文件放到jre/lib/ext目录下,还有第二个缺陷:有时侯,程序员忘记了他很久以前放在这个目录下的类文件。当class loader似乎忽略了类路径(其实没有,因为类加载总是先让父的类加载器加载类,只有父的类加载器加载不了的话才由自己来加载,“extension class loader是system class loader的父,因此。.”),而加载了放在扩展目录下的遗忘已久的类的时候,他们就会迷惑不解。class loader有父子关系,bootstrap class loader以外的

7、每一个class loader都有一个父的类加载器。类加载器会给父的加载器一个机会加载任何给定的类,如果父加载器加载失败的话自身才去加载。举个例子,当系统class loader被要求加载一个系统类的时候(比如,java.util.ArrayList),那么,首先需要extension class loader加载,而extension class loader又先让bootstrap class loader,最终由bootstrap class loader查找并且加载了rt.jar,其他任何类加载器不需要再搜索。注意:当实现一个类加载器的时候,你应该总是授权父加载器去加载类。否则,将会有

8、一些潜在的安全隐患:自定义的类加载器可能避开重要的安全检查,意外地加载了系统类。Applets, servlets, and RMI stubs是用户自定义的类加载器加载的。你甚至可以根据自己的需要写自己的类加载器。这种方式允许你在传字节码给虚拟机之前实现特殊的安全检查。比如,你可以写一个类加载器拒绝加载没有用“paid for”表示的类。下一节将展示这么去实现。大多数时间,你不需要担心类加载器。很多类因为被其他类引用而被加载,这个过程对你来说是透明的。如果你在程序里调用Class.forName来加载一个类,那么一个新的类被调用Class.forName的类的加载器加载。通常,这不会有什么问

9、题。然而,在下面的情况下将会失败:1、你的lib自己实现了一个有Class.forName方法的类的时候2、你的lib里的类的方法被一个不同的类加载器加载的应用程序类所调用的时候(这一先需要好好理解)3、被加载的类对于应用程序的类加载器来说是不可见的时候(也就是说classpath下没有相关的类)这种情况下。库类需要搜索应用程序类加载器(代码如下):Thread t = Thread.currentThread();ClassLoader loader = t.getContextClassLoader();Class cl = loader.loadClass(className);Usin

10、g Class Loaders as Namespaces任何一个java程序员都知道包名是用来消除名字冲突的。在标准类库里有两个叫Date的类(java.util.Date and java.sql.Date)。简单的名字(这里指的是你在程序里直接写Date)只是程序员方便,并且需要包含import语句。在一个运行的程序中,所有的class都包含他们的包名。这也许让你吃惊,然而,在同一个虚拟机里面你可以有两个类名和包名都相同的类。一个类是通过他的全名和类加载器来标识的。This technique is useful for loading code from multiple source

11、s.比如,浏览器为每个web页面使用单独的applet class loader.这允许虚拟机分开来自不同web页面的类,不管他们是怎么命名的。NOTE:这项技术还有其他的用途,比如Sevlet和EJB的“热部署”,请参照:http:/ /TechTips/2000/tt1027.htmlWriting Your Own Class LoaderThe loadClass method of the ClassLoader superclass takes care of the delegation tothe parent and calls findClass only if the c

12、lass hasnt already been loaded andif the parent class loader was unable to load the class.定义自己的类加载器只需要继承ClassLoader类并且重写findClass(String className)方法。ClassLoader父类的loadClass方法负责授权给父的类加载器 并且只有在还没有加载并且父的类加载器不能加载的时候才调用findClass方法。NOTE:在早期版本的JDK中,程序员必须重写loadClass方法。现在不再建议这种做法。实现findClass方法必须做下面两件事情1、从文件

13、或者其他地方加载类的字节码2、为了把字节码提交给虚拟机,需要调用ClassLoader类的defineClass方法,以下是实现一个加载加密类文件的类加载器。/* This class loader loads encrypted class files.*/class CryptoClassLoader extends ClassLoader /* Constructs a crypto class loader.* param k* the decryption key*/public CryptoClassLoader(int k) key = k;protected Class fin

14、dClass(String name) throws ClassNotFoundException byte classBytes = null;try classBytes = loadClassBytes(name); catch (IOException e) throw new ClassNotFoundException(name);Class cl = defineClass(name, classBytes, 0, classBytes.length);if (cl = null)throw new ClassNotFoundException(name);return cl;/

15、* Loads and decrypt the class file bytes.* param name* the class name* return an array with the class file bytes*/private byte loadClassBytes(String name) throws IOException String cname = name.replace(。, /) + “.caesar”;FileInputStream in = null;in = new FileInputStream(cname);try ByteArrayOutputStr

16、eam buffer = new ByteArrayOutputStream();int ch;while (ch = in.read() != -1) byte b = (byte) (ch - key);buffer.write(b);in.close();return buffer.toByteArray(); finally in.close();private int key;看看怎么实现一个自己的ClassLoader(我们以web应用的classloader为例来讲解)大家都很熟悉tomcat,比如我们要写一个servlet运行的话。1、我们通常会在tomcat的webapps目

17、录下建一个自己的web目录(比如myweb),然后让自己的myweb至少具有以下目录结构。WEB-INFclasseslib2、直接把class文件拷贝到classes目录下,或者把自己做的servet打成jar放到lib下3、启动tomcat就能访问servlet了。再说一点:不少人了解struts,也做过基于struts的应用。其实struts对于我们来说只是几个jar而已,我们要在自己的应用中用 struts,只不过就象上面一样把struts的各个lib拷贝到web应用的WEB-INF/lib下就OK了。再综合前面的基础部分,其实web应用是有自己的classloader的,他专门负责加

18、载WEB-INF/lib和WEB-INF /classes的类。下面我们就来模拟一下web应用的classloader,相信看了下面的代码你就会对classloader的理解又上一个台阶。import java.io.File;import java.io.FilenameFilter;import java.lang.reflect.Method;import .MalformedURLException;import .URL;import .URLClassLoader;/* web应用的classloader* 带你步入classloader的天堂*/public class WebA

19、ppClassLoaderURLClassLoader myClassLoader = null;/* 用法:new WebAppClassLoader(webRoot)* 比如:new WebAppClassLoader(“c:/web”)*/public WebAppClassLoader(String root) URL urls = null;try urls = getJarURLs(root); catch (MalformedURLException e) System.out.println(e.getMessage();myClassLoader = new URLClass

20、Loader(urls);/* 获得web应用下的所有class的path的URL.* 1、WEB-INFclasses目录* 2、WEB-INFlib下的所有jar文件*/private URL getJarURLs(String rootDirStr) throws MalformedURLException if (!rootDirStr.endsWith(File.separator) rootDirStr += File.separator;/ classesDir就是web应用中的“WEB-INFclasses”目录File classesDir = new File(rootDi

21、rStr + File.separator + “WEB-INF”+ File.separator + “classes”);/ classesDir就是web应用中的“WEB-INFlib”目录File libDir = new File(rootDirStr + File.separator + “WEB-INF”+ File.separator + “lib”);/ 找出目录下所有的jar文件File jarFiles = null;if (libDir.isDirectory() jarFiles = libDir.listFiles(new FilenameFilter() publ

22、ic boolean accept(File dir, String name) / 注意“dir”参数指的是jar文件的父目录,“name”才是jar文件的if (dir.isDirectory() / jar文件的父目录必须是一个文件夹& (name.endsWith(“.jar”) | name.endsWith(“.zip”) / 注意zip文件也是可以的哦return true;return false;);int jarCount = null = jarFiles?0:jarFiles.length;URL urls = new URL1 + jarCount;urls0 = c

23、lassesDir.toURI().toURL();/WEB-INFclassesfor (int i = 0; i jarCount; i+) /WEB-INFlib下的所有jar文件urlsi + 1 = jarFilesi.toURI().toURL();return urls;/*加载class,直接调用 myClassLoader的loadClass(className)方法*/public Class loadClass(String className) throws ClassNotFoundExceptionreturn myClassLoader.loadClass(cla

24、ssName);/* 测试WebAppClassLoader* param args*/public static void main(String mainArgs) try /请根据实际情况指定目录和类名WebAppClassLoader classLoader = new WebAppClassLoader(“c:/web/”);Class c = classLoader.loadClass(“classloader.ButtonTest”);/用反射调用main方法String args = new String ;Method m = c.getMethod(“main”, args

25、.getClass();m.invoke(null, (Object) args); catch (Exception e) / handle exceptione.printStackTrace();测试自己的ClassLoader1、在c盘建一个web目录(当然了,你可以把上面类的main改一下 使他适合自己的需求),然后子目录如下WEB-INFclasseslib2、新写一个带main方法的类:classloader.ButtonTest(当然了,你可以把上面类的main改一下 使他适合自己的需求),然后打包成jar文件 放到web/WEB-INF/lib下(当然了,你也可以不打包,直接

26、把你的类放到web/WEB-INF/classes下),如果你很懒,就copy 我下面的代码吧,顺便还可以了解了解AWT和SWING;#这个ButtonTest的main方法也可以不象下面这么复杂,就一个 System.out.print也可以的哦package classloader;import java.awt.*;import java.awt.event.*;import javax.swing.*;public class ButtonTestpublic static void main(String args)ButtonFrame frame = new ButtonFram

27、e();frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);/*A frame with a button panel*/class ButtonFrame extends JFramepublic ButtonFrame()setTitle(“ButtonTest”);setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);/ add panel to frameButtonPanel panel = new ButtonPanel();add(panel);public

28、 static final int DEFAULT_WIDTH = 300;public static final int DEFAULT_HEIGHT = 200;/*A panel with three buttons.*/class ButtonPanel extends JPanelpublic ButtonPanel()/ create buttonsJButton yellowButton = new JButton(“Yellow”);JButton blueButton = new JButton(“Blue”);JButton redButton = new JButton(

29、“Red”);/ add buttons to paneladd(yellowButton);add(blueButton);add(redButton);/ create button actionsColorAction yellowAction = new ColorAction(Color.YELLOW);ColorAction blueAction = new ColorAction(Color.BLUE);ColorAction redAction = new ColorAction(Color.RED);/ associate actions with buttonsyellow

30、Button.addActionListener(yellowAction);blueButton.addActionListener(blueAction);redButton.addActionListener(redAction);/*An action listener that sets the panels background color.*/private class ColorAction implements ActionListenerpublic ColorAction(Color c)backgroundColor = c;public void actionPerformed(ActionEvent event)setBackground(backgroundColor);private Color backgroundColor;3、运行上面的WebAppClassLoader,看看你自己写的,放在web/WEB-INF/lib下的有没有被调用,被调用的话就恭喜你了。请注意:不要把你新写的带main方法的类放在WebAppClassLoader所在的工程目录下,如果你这样做的话起不到测试效果,因为这样的话类不需要自己写的WebAppClassLoader也能被load着的。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 社会民生


经营许可证编号:宁ICP备18001539号-1