package com.github.ltsopensource.core.spi;
import com.github.ltsopensource.core.commons.utils.Assert;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @author Robert HG (254963746@qq.com)on 12/23/15.
*/
public final class ClassLoaderUtil {
private static final ConstructorCache CONSTRUCTOR_CACHE = new ConstructorCache();
private ClassLoaderUtil() {
}
@SuppressWarnings("unchecked")
public static <T> T newInstance(ClassLoader classLoader, final String className) throws Exception {
classLoader = classLoader == null ? ClassLoaderUtil.class.getClassLoader() : classLoader;
Constructor<T> constructor = CONSTRUCTOR_CACHE.get(classLoader, className);
if (constructor != null) {
return constructor.newInstance();
}
Class<T> clazz = (Class<T>) loadClass(classLoader, className);
return (T) newInstance(clazz, classLoader, className);
}
public static <T> T newInstance(Class<T> clazz, ClassLoader classLoader, String className) throws Exception {
final Constructor<T> constructor = clazz.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
CONSTRUCTOR_CACHE.put(classLoader, className, constructor);
return constructor.newInstance();
}
public static Class<?> loadClass(final ClassLoader classLoader, final String className)
throws ClassNotFoundException {
Assert.notNull(className, "className");
ClassLoader theClassLoader = classLoader;
if (theClassLoader == null) {
theClassLoader = Thread.currentThread().getContextClassLoader();
}
if (theClassLoader != null) {
try {
return tryLoadClass(className, theClassLoader);
} catch (ClassNotFoundException ignore) {
}
}
return Class.forName(className);
}
private static Class<?> tryLoadClass(String className, ClassLoader classLoader)
throws ClassNotFoundException {
if (className.startsWith("[")) {
return Class.forName(className, false, classLoader);
} else {
return classLoader.loadClass(className);
}
}
private static final class ConstructorCache {
private final ConcurrentMap<ClassLoader, ConcurrentMap<String, WeakReference<Constructor>>> cache;
private ConstructorCache() {
cache = new ConcurrentHashMap<ClassLoader, ConcurrentMap<String, WeakReference<Constructor>>>();
}
private <T> Constructor put(ClassLoader classLoader, String className, Constructor<T> constructor) {
ClassLoader cl = classLoader == null ? ClassLoaderUtil.class.getClassLoader() : classLoader;
ConcurrentMap<String, WeakReference<Constructor>> innerCache = cache.get(cl);
if (innerCache == null) {
innerCache = new ConcurrentHashMap<String, WeakReference<Constructor>>(100);
ConcurrentMap<String, WeakReference<Constructor>> old = cache.putIfAbsent(cl, innerCache);
if (old != null) {
innerCache = old;
}
}
innerCache.put(className, new WeakReference<Constructor>(constructor));
return constructor;
}
@SuppressWarnings("unchecked")
public <T> Constructor<T> get(ClassLoader classLoader, String className) {
Assert.notNull(className, "className");
ConcurrentMap<String, WeakReference<Constructor>> innerCache = cache.get(classLoader);
if (innerCache == null) {
return null;
}
WeakReference<Constructor> reference = innerCache.get(className);
Constructor constructor = reference == null ? null : reference.get();
if (reference != null && constructor == null) {
innerCache.remove(className);
}
return (Constructor<T>) constructor;
}
}
}