java类加载扩展

  • URLClassLoader加载类
    该类加载器用于从指向 JAR 文件和目录的 URL 的搜索路径加载类和资源。
  • 从class文件字节流加载
    通过调用ClassLoader类的defineclass()方法加载类;
    将一个 byte 数组转换为 Class 类的实例。必须分析 Class,然后才能使用它。
  • 从jar文件字节流动态加载类
    通过JarFile 和JarEntry分析Jar文件条目,读取相应的class byte[], 调用definclass 加载;
    JarInputStream 需要先转成File 在转换成JarFile进行加载

完整代码

package com.yun.hop.commons.classloader;

import com.shuyun.evtsvc.EventProcessContext;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Created by hop 2016/4/7.
 * description:
 */
public class ByteClassLoader extends URLClassLoader {

    //缓存加载的Class类
    private final Hashtable cache = new Hashtable();
    private static Logger LOG = LoggerFactory.getLogger(ByteClassLoader.class);

    public ByteClassLoader(ClassLoader parent) {
        super(new URL[0], parent);
    }

    //从class文件的字节数组byte[]加载class
    public synchronized Class loadClass(String name, byte[] clazz, boolean resolve)
            throws ClassNotFoundException {
        if (name.startsWith("java.")) {
            return findSystemClass(name);
        }
        Class c = (Class) cache.get(name);
        if (c == null) {

            c = defineClass(name, clazz, 0, clazz.length);
            cache.put(name, c);
        } else {
            LOG.info("loadClass: found " + name + " in cache.");
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }

    //从jar文件的字节数组加载jar包中的类
    public synchronized Class loadClassFromJar(String className, byte[] jarFileBytes, boolean resolve)
            throws ClassNotFoundException {
        File tempFile = null;
        JarFile jarFile = null;
        String jarEntryName = className.replaceAll("\\.", "\\/") + ".class";
        try {
            //通过把jar字节数组写到临时文件的方式加载
            tempFile = File.createTempFile("tempJarFile", "jar");
            FileUtils.writeByteArrayToFile(tempFile, jarFileBytes);
            jarFile = new JarFile(tempFile);
            Enumeration jarEntrys = jarFile.entries();


            while (jarEntrys.hasMoreElements()) {
                JarEntry jarEntry = jarEntrys.nextElement();
                if (jarEntry.getName().equals(jarEntryName)) {
                    byte bytes[] = IOUtils.toByteArray(jarFile.getInputStream(jarEntry));
                    return loadClass(className, bytes, true);
                }
            }

        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        } finally {
            try {
                if (jarFile != null) {
                    jarFile.close();
                }
                if (tempFile != null) {
                    tempFile.delete();
                }

            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
            }

        }

        return null;

    }


    public void testUrlClassloader(File file) {
        try {
            URL[] urls = new URL[1];
            urls[0] = file.toURI().toURL();
            //URLClassLoader 从本地jar文件加载相应的类
            URLClassLoader urlClassLoader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
            Class.forName("com.yun.hop.apitest.Out", true, urlClassLoader);
            Class classz = Class.forName("com.yun.hop.apitest.OutA", true, urlClassLoader);
            Object object = classz.newInstance();
            Method method = classz.getMethod("out", String.class);
            method.invoke(object, "Hello test testUrlClassloader");

        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }

    }

    public void testClassLoaderFromJar() {
        String filePath = "F:/class/apitest-0.0.1-SNAPSHOT.jar";
        try {
            Class classz1 = loadClassFromJar("com.yun.hop.apitest.Out", //
                    IOUtils.toByteArray(FileUtils.openInputStream(new File(filePath))), //
                    true);
            Class classz = loadClassFromJar("com.yun.hop.apitest.OutA", //
                    IOUtils.toByteArray(FileUtils.openInputStream(new File(filePath))), //
                    true);

            Object object = classz.newInstance();
            Method method = classz.getMethod("out", String.class);
            method.invoke(object, "Hello test testClassLoaderFromJar");
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
    }


    public void testClassLoader() {
        try {
            Class classz1 = loadClass("com.yun.hop.apitest.Out", //
                    IOUtils.toByteArray(FileUtils.openInputStream(new File("F:/class/Out.class"))),//
                    true//
            );
            Class classz = loadClass("com.yun.hop.apitest.OutA", //
                    IOUtils.toByteArray(FileUtils.openInputStream(new File("F:/class/OutA.class"))),//
                    true//
            );
            Object object = classz.newInstance();
            Method method = classz.getMethod("out", String.class);
            method.invoke(object, "Hello test classloader");

        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }


    }

    public static void main(String args[]) {

        ByteClassLoader byteClassLoader = new ByteClassLoader(Thread.currentThread().getContextClassLoader());
        byteClassLoader.testUrlClassloader(new File("F:/class/apitest-0.0.1-SNAPSHOT.jar"));
        byteClassLoader.testClassLoader();
        byteClassLoader.testClassLoaderFromJar();
    }

}

你可能感兴趣的:(Java)