您的位置:首页 > 编程语言 > Java开发

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构造中没有指定父类加载器,因此插件类的父类就是系统类加载器(应用类)。



类加载器倒置:
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中,可以有两个类,它们的包名和类名都相同,这是因为类是由它人全名和类加载器来确定的。



类加载器应用场景:加密软件,将类文件存储到数据库等

定制类加载器

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时,这些字节码首先要接受“校验器”的校验,除了系统类外,所有的类都要校验。

安全管理器
字节码通过校验后,第二种安全机制就会启动,安全管理器是一个负责控制具体操作是否允许执行类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: