JAVA基础之类加载器
2015-12-01 00:00
316 查看
编译器:为JVM转换源指令,将.java文件转换为.class的字节码文件;
解释器:将字节码文件翻译成目标机器的机器语言;
JVM仅加载程序执行时所需要的类文件,假设程序从MyProgram.class开始运行,其过程如下:
类加载:从磁盘上读取文件或请求Web上的文件,加载MyProgram.class中的内容;
类分析:如果MyProgram.class中存在类型为另一个类的域,或者是拥有超类,那么这些类文件也会被加载;
接着,JVM执行MyProgram中的main方法(它是静态的,无需创建类的实例);
如果main方法或者main调用的方法要用到更多的类,那么接下来会加载这些类。
类加载器分类:
引导类加载器:加载系统类,通常从rt.jar开始,通常是用C语言来实现;
扩展类加载器:加载jre/lib/ext中的标准扩展类,不产生类路径;
系统类加载器(应用类加载器):加载应用类,CLASSPATH配置的类文件,产生类路径;
类加载器的层次结构:
类加载器有一种父/子关系,除了引导类加载器外,每个类加载都有一个父类加载器;加载类的时候,父类有一次加载机会,只有父类加载失败才加载指定的类:
URL url = new URL("file:///*.jar");
URLClassLoader pluginLoader = new URLClassLoader(new URL[]{url});
Class<?> cl = pluginLoader.loadClass("myPackage.MyClass");
因为在URLClassLoader构造中没有指定父类加载器,因此插件类的父类就是系统类加载器(应用类)。
![](http://static.oschina.net/uploads/space/2015/1201/112140_iQ7O_2500345.jpg)
类加载器倒置:
Class.forName()使用的是系统类加载器(应用类),如果有一个插件类希望被类加载器加载,系统类加载器对插件类是不可见的,所以就需要使用插件类加载器。
每个线程都有一个对类加载器的引用,称为上下文类加载器。主线程的上下文类加载器是系统类加载器,所以,如果不作任何操用,所有的线程都会是系统类加载器。
在同一个JVM中,可以有两个类,它们的包名和类名都相同,这是因为类是由它人全名和类加载器来确定的。
![](http://static.oschina.net/uploads/space/2015/1201/133229_L6Hb_2500345.jpg)
类加载器应用场景:加密软件,将类文件存储到数据库等
定制类加载器
字节码校验
当类加载器将新加载的Java平台类的字节码传递给JVM时,这些字节码首先要接受“校验器”的校验,除了系统类外,所有的类都要校验。
安全管理器
字节码通过校验后,第二种安全机制就会启动,安全管理器是一个负责控制具体操作是否允许执行类。
解释器:将字节码文件翻译成目标机器的机器语言;
JVM仅加载程序执行时所需要的类文件,假设程序从MyProgram.class开始运行,其过程如下:
类加载:从磁盘上读取文件或请求Web上的文件,加载MyProgram.class中的内容;
类分析:如果MyProgram.class中存在类型为另一个类的域,或者是拥有超类,那么这些类文件也会被加载;
接着,JVM执行MyProgram中的main方法(它是静态的,无需创建类的实例);
如果main方法或者main调用的方法要用到更多的类,那么接下来会加载这些类。
类加载器分类:
引导类加载器:加载系统类,通常从rt.jar开始,通常是用C语言来实现;
扩展类加载器:加载jre/lib/ext中的标准扩展类,不产生类路径;
系统类加载器(应用类加载器):加载应用类,CLASSPATH配置的类文件,产生类路径;
类加载器的层次结构:
类加载器有一种父/子关系,除了引导类加载器外,每个类加载都有一个父类加载器;加载类的时候,父类有一次加载机会,只有父类加载失败才加载指定的类:
URL url = new URL("file:///*.jar");
URLClassLoader pluginLoader = new URLClassLoader(new URL[]{url});
Class<?> cl = pluginLoader.loadClass("myPackage.MyClass");
因为在URLClassLoader构造中没有指定父类加载器,因此插件类的父类就是系统类加载器(应用类)。
![](http://static.oschina.net/uploads/space/2015/1201/112140_iQ7O_2500345.jpg)
类加载器倒置:
Class.forName()使用的是系统类加载器(应用类),如果有一个插件类希望被类加载器加载,系统类加载器对插件类是不可见的,所以就需要使用插件类加载器。
每个线程都有一个对类加载器的引用,称为上下文类加载器。主线程的上下文类加载器是系统类加载器,所以,如果不作任何操用,所有的线程都会是系统类加载器。
URL url = new URL("file:///*.jar"); URLClassLoader pluginLoader = new URLClassLoader(new URL[]{url}); //设置上下文类加载器为指定的类加载器 Thread t = Thread.currentThread(); t.setContextClassLoader(pluginLoader); //调用类 Class<?> cl = pluginLoader.loadClass("myPackage.MyClass")
在同一个JVM中,可以有两个类,它们的包名和类名都相同,这是因为类是由它人全名和类加载器来确定的。
![](http://static.oschina.net/uploads/space/2015/1201/133229_L6Hb_2500345.jpg)
类加载器应用场景:加密软件,将类文件存储到数据库等
定制类加载器
import java.io.FileInputStream; import java.io.FileOutputStream; public class Caesar { public static void main(String[] args) { if (args.length != 3) { System.out.println("USAGE: java classloader.Caesar in out key"); return; } try { FileInputStream in = new FileInputStream(args[0]); FileOutputStream out = new FileOutputStream(args[1]); int key = Integer.parseInt(args[2]); int ch = 0; while ((ch = in.read()) != -1) { byte c = (byte) (ch + key); out.write(c); } } catch (Exception e) { } } }
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class CryptoClassLoader extends ClassLoader { private int key; public CryptoClassLoader(int key) { this.key = key; } protected Class<?> findClass(String name) throws ClassNotFoundException { try { byte[] classBytes = null; classBytes = loadClassBytes(name); //调用超类ClassLoader的defineClass方法,向JVM提供字节码 Class<?> cl = defineClass(name, classBytes, 0, classBytes.length); if (cl == null) throw new ClassNotFoundException(name); return cl; } catch (Exception e) { throw new ClassNotFoundException(name); } } private byte[] loadClassBytes(String name) throws IOException { String cname = name.replace('.', '/') + ".caesar"; InputStream in = new FileInputStream(new File(cname)); byte[] bytes = toByteArray(in); for (int i = 0; i < bytes.length; i++) bytes[i] = (byte) (bytes[i] - key); in.close(); return bytes; } //字符流转字节流 private byte[] toByteArray(InputStream in) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int offset = 0; while ((offset = in.read(buffer)) != -1) { out.write(buffer, 0, offset); } out.close(); return out.toByteArray(); } }
import java.awt.GridBagConstraints; public class GBC extends GridBagConstraints { public GBC(int gridx, int gridy) { this.gridx = gridx; this.gridy = gridy; } public GBC(int gridx, int gridy, int gridwidth, int gridheight) { this.gridx = gridx; this.gridy = gridy; this.gridwidth = gridwidth; this.gridheight = gridheight; } public GBC setSpan(int gridwidth, int gridheight) { this.gridwidth = gridwidth; this.gridheight = gridheight; return this; } public GBC setAnchor(int anchor) { this.anchor = anchor; return this; } public GBC setFill(int fill) { this.fill = fill; return this; } public GBC setWeight(double weightx, double weighty) { this.weightx = weightx; this.weighty = weighty; return this; } public GBC setInsets(int distance) { this.insets = new java.awt.Insets(distance, distance, distance, distance); return this; } public GBC setInsets(int top, int left, int bottom, int right) { this.insets = new java.awt.Insets(top, left, bottom, right); return this; } public GBC setIpad(int ipadx, int ipady) { this.ipadx = ipadx; this.ipady = ipady; return this; } }
import java.awt.GraphicsConfiguration; import java.awt.GridBagLayout; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.Method; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTextField; public class ClassLoaderFrame extends JFrame { private JTextField keyField = new JTextField("3", 4); private JTextField nameField = new JTextField("Calculator", 30); private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HIENGTH = 200; public ClassLoaderFrame() throws HeadlessException { setSize(DEFAULT_WIDTH, DEFAULT_HIENGTH); setLayout(new GridBagLayout()); add(new JLabel("Class"), new GBC(0, 0).setAnchor(GBC.EAST)); add(nameField, new GBC(1, 0).setWeight(100, 0).setAnchor(GBC.WEST)); add(new JLabel("Key"), new GBC(0, 1).setAnchor(GBC.EAST)); add(keyField, new GBC(1, 1).setWeight(100, 0).setAnchor(GBC.WEST)); JButton loadButton = new JButton("Load"); add(loadButton, new GBC(0, 2, 2, 1)); loadButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { runClass(nameField.getText(), keyField.getText()); } }); } public void runClass(String name, String key) { try { //调用classloader,传递解密key ClassLoader loader = new CryptoClassLoader(Integer.parseInt(key)); Class<?> c = loader.loadClass(name); Method m = c.getMethod("main", String[].class); m.invoke(null, (Object) new String[] {}); } catch (Throwable e) { JOptionPane.showMessageDialog(this, e); } } public ClassLoaderFrame(GraphicsConfiguration gc) { super(gc); } public ClassLoaderFrame(String title) throws HeadlessException { super(title); } public ClassLoaderFrame(String title, GraphicsConfiguration gc) { super(title, gc); } }
import java.awt.EventQueue; import javax.swing.JFrame; public class ClassLoaderTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new ClassLoaderFrame(); frame.setTitle("ClassLoaderTest"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } }
字节码校验
当类加载器将新加载的Java平台类的字节码传递给JVM时,这些字节码首先要接受“校验器”的校验,除了系统类外,所有的类都要校验。
安全管理器
字节码通过校验后,第二种安全机制就会启动,安全管理器是一个负责控制具体操作是否允许执行类。
相关文章推荐
- Java中Map遍历的四种方法
- Spring scheduling tasks 执行时机
- Java中使用OpenSSL生成的RSA公私钥进行数据加解密
- java 使用 ftp下载文件失败的问题
- 第一章 Web MVC 简介(转)
- JAVA单态设计模式
- spring容器和装配Bean:
- java的接口回调
- spring 的事务属性二——事务传播行为
- java设计模式---模板方法模式
- 【最新】最流行的java后台框架 springmvc mybaits 集代码生成器
- Java properities 中文乱码解决方法
- 【转】java 注释规范
- Spring 事务的梳理一——事务的属性
- java 学习心得3
- ubuntu 在线安装jdk1.6 1.7 1.8
- ResourceBundle、Locale
- 给Java程序猿们推荐一些值得一看的好书
- JAVA语法基础要点
- java学习笔记之多线程(1)之创建线程