一、JVM启动顺序
JVM预定义的三种类型类加载器,当一个 JVM 启动的时候,Java 缺省开始使用如下三种类型类装入器:
启动(Bootstrap)类加载器:引导类装入器是用本地代码实现的类装入器,它负责将 <Java_Runtime_Home>/lib 下面的类库加载到内存中。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。 标准扩展(Extension)类加载器:扩展类加载器是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader) 实现的。它负责将 < Java_Runtime_Home >/lib/ext 或者由系统变量 java.ext.dir 指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。
系统(System)类加载器:系统类加载器是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加载器。
除了以上列举的三种类加载器,还有一种比较特殊的类型就是线程上下文类加载器。
需要着重说明的是,JVM在加载类时默认采用的是双亲委派机制。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
【疑问】为什么要使用这种双亲委托模式呢?
第一个原因就是因为这样可以
避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
第二个原因就是考虑到
安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。
二、类加载过程:
1、加载:查找并加载类的二进制文件。本步骤的目的在于加载二进制的.class文件到内存中。
2、连接:包括验证、准备和解析类的二进制数据
(1)验证:确保被加载类的正确性。存在有人修改过字节码的情况, 顺便补充一下java的字节码是有一定标准的,具体参考Java字节码的官方文档。
(2)准备:为类的静态变量分配内存,并将其初始化为默认值。 【注意】是默认值, 默认情况下:int -> 0, short -> 0, long -> 0, float -> 0.0f, double -> 0.0, char -> ' ', byte -> 0, boolean -> false
(3)解析:把类中的符号引用解析为直接引用
3、初始化:为类的静态变量初始化
三、类加载器的扩展
继承自ClassLoader类
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Set;
- import java.util.jar.JarEntry;
- import java.util.jar.JarFile;
- import playground.library.functional.FunctionalUtils;
- import playground.library.functional.Pair;
- import playground.library.functional.iterator.FilterIterator;
- import playground.library.functional.iterator.IteratorTransformer;
- import playground.library.functional.Predicate;
- import playground.library.functional.Transformer;
- import playground.library.functional.iterator.DelegatingIterator;
- import playground.library.functional.iterator.LinkingIterator;
- import playground.library.jar.JarEntryIterator;
- import playground.library.utils.IteratorUtils;
- import playground.library.utils.IOUtils;
-
-
-
-
- public class JarClassLoader extends ClassLoader
- {
- public JarClassLoader(ClassLoader parent) { super(parent); }
- public JarClassLoader() { super(); }
-
- private final List<JarFile> files = new ArrayList<JarFile>();
-
-
-
-
-
- private Iterator<Pair<JarFile, JarEntry>> getResources(){
- return new LinkingIterator<Pair<JarFile, JarEntry>>(
- new IteratorTransformer<JarFile, Iterator<Pair<JarFile,JarEntry>>>(
- new Transformer<JarFile, Iterator<Pair<JarFile, JarEntry>>>(){
- public Iterator<Pair<JarFile, JarEntry>> transform(JarFile file){
- return FunctionalUtils.merge(file, new JarEntryIterator(file));}})
- .transform(JarClassLoader.this.files.iterator()));}
-
-
-
-
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException{
- final Iterator<Pair<JarFile,JarEntry>> resources = this.getResources();
- while (resources.hasNext()){
- final Pair<JarFile, JarEntry> resource = resources.next();
- if(resource.second.getName().equals(name)){
- try { return this.load(resource.first.getInputStream(resource.second));}
- catch (IOException e) { e.printStackTrace(); }}}
- throw new ClassNotFoundException();}
-
-
-
-
-
-
- private Class<?> load(final InputStream input){
- try {
- final ByteArrayOutputStream output = new ByteArrayOutputStream();
- final byte[] bytes = IOUtils.copy(input, new ByteArrayOutputStream()).toByteArray();
- return this.defineClass(null, bytes, 0, bytes.length); }
- catch (IOException e){ throw new RuntimeException(e); }
- finally{
- try{ input.close(); }
- catch (IOException e){ throw new RuntimeException(e);}}}
-
-
-
-
-
-
- public Iterator<Class<?>> load(final JarFile file) throws IOException{
- this.files.add(file);
-
- return
- new DelegatingIterator<Class<?>>(
- new IteratorTransformer<JarEntry, Class<?>>(
- new Transformer<JarEntry, Class<?>>(){
- public Class transform(JarEntry stream){
- InputStream fileStream = null;
-
- try{ return JarClassLoader.this.load(fileStream = file.getInputStream(stream)); }
- catch(IOException e){ throw new RuntimeException(e);}
- finally{IOUtils.close(fileStream); }}})
- .transform(
- new FilterIterator(
- new Predicate<JarEntry>(){
- public boolean satisfies(JarEntry entry){
- return entry.getName().endsWith(".class");}},
- new JarEntryIterator(file)))){
- @Override
- public Class<?> next(){
- final Class<?> clazz = super.next();
- if (!this.hasNext()) JarClassLoader.this.files.remove(file);
- return clazz;}
-
- @Override
- public boolean hasNext(){
- final boolean hasNext = super.hasNext();
- if (!hasNext) JarClassLoader.this.files.remove(file);
- return hasNext;}};}
-
-
-
-
- public Set<Class<?>> loadAll(final JarFile file) throws IOException
- {
- return IteratorUtils.fill(new HashSet<Class<?>>(), this.load(file));
- }
- }
本文转自 tianya23 51CTO博客,原文链接:http://blog.51cto.com/tianya23/475112,如需转载请自行联系原作者