All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.icodegarden.commons.lang.classloader.InputStreamClassLoader Maven / Gradle / Ivy

package io.github.icodegarden.commons.lang.classloader;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;

/**
 * 
 * @author Fangfang.Xu
 *
 */
public final class InputStreamClassLoader extends ClassLoader {

	private final String className;
	private InputStream is;
	private ClassLoader appClassLoader;

	/**
	 * 
	 * @param className 完整类名,例如io.github.icodegarden.commons.lang.classloader.Tester
	 * @param is
	 * @throws IOException
	 */
	public InputStreamClassLoader(String className, InputStream is) throws IOException {
		super(null);// 脱离双亲,否则无法重复加载classpath下的class
		if (is.available() == 0) {
			throw new IOException("InputStream's available must > 0");
		}
		this.className = className;
		appClassLoader = getSystemClassLoader();
		this.is = is;
	}

	/**
	 * 类加载的入口,给客户端一个友好的接口,不用指定name
	 * 
	 * @return 加载完成的类
	 */
	public Class loadClass() throws ClassNotFoundException {
		return loadClass(className);
	}

	/**
	 * 客户端可以直接使用该接口创建实例,而不需要先使用 {@link #loadClass()}
	 * 
	 * @param interfaceClass 必须指定接口
	 * @param initargs       构造参数
	 * @return 新的实例
	 */
	public  T newInstance(Class interfaceClass, Object... initargs) throws Exception {
		if (!interfaceClass.isInterface()) {
			throw new IllegalArgumentException("class " + interfaceClass.getName() + " is not a interface");
		}
		Class loaded = loadClass();

		Class[] parameterTypes = null;
		if (initargs != null && initargs.length > 0) {
			parameterTypes = new Class[initargs.length];
			for (int i = 0; i < initargs.length; i++) {
				parameterTypes[i] = initargs[i].getClass();
			}
		}
		Constructor declaredConstructor = loaded.getDeclaredConstructor(parameterTypes);
		return (T) declaredConstructor.newInstance(initargs);
	}

	/**
	 * 时序:
	 * 第1次进来:加载name指定的类,如io.github.icodegarden.commons.lang.classloader.Tester,此时从stream中读取bytes并触发defineClass(...)
* 第2次进来:加载依赖的接口,例如io.github.icodegarden.commons.lang.classloader.ITester,而接口应使用已加载的class而不需要重新加载,所以进到if分支内
*/ @Override protected Class findClass(String name) throws ClassNotFoundException { try { if (is == null) { // return appClassLoader.loadClass(name); /** * 通常用appClassLoader是可以的,因为由appClassLoader负责加载classpath下的类
* 但在spring环境下可能是被org.springframework.boot.loader.LaunchedURLClassLoader加载而不是appClassLoader
* 因此用Class.forName(name); */ return Class.forName(name); } byte[] b = new byte[is.available()]; is.read(b); is = null; return defineClass(name, b, 0, b.length); } catch (IOException e) { throw new ClassNotFoundException(name, e); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy