我尝试在一个java swing应用程序中设置两个Oracle Coherence near缓存实例。可以找到解决方案的想法here。我的情况有点复杂,这是游戏开始的地方。
在我的情况下,有帐户服务。它可以有两个端点:SIT和UAT。为了创建两个这样的服务,我需要加载Coherence的两个“实例”,以便用系统变量覆盖端点( tangosol.coherence.cacheconfig )。
我有:
bin: startup.bat, startup.sh conf: app.properties lib: mainapp.jar, account-interfaces.jar, account-impl.jar, coherence.jar
我创建了一个专用的child-first classLoader --InverseClassLoader,并创建了AppLaunchClassLoader(默认的Thread.currentThread()。GetContextClassLoader()classLoader)它的父级。使用InverseClassLoader,我加载了AccountServiceImpl类:
Class<AccountServiceImpl> acImplClass = contextClassLoader.selfLoad(AccountServiceImpl.class).loadClass(AccountServiceImpl.class);
Constructor<AccountServiceImpl> acConstructor =
acImplClass .getConstructor(String.class);
AccountService acService = acConstructor .newInstance(serviceURL);
这是InverseClassLoader:
public class InvertedClassLoader extends URLClassLoader {
private final Set<String> classesToNotDelegate = new HashSet<>();
public InvertedClassLoader(URL... urls) {
super(urls, Thread.currentThread().getContextClassLoader());
}
public InvertedClassLoader selfLoad(Class<?> classToNotDelegate) {
classesToNotDelegate.add(classToNotDelegate.getName());
return this;
}
@Override
public Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
if (shouldNotDelegate(className)) {
System.out.println("CHILD LOADER: " + className);
Class<?> clazz = findClass(className);
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
else {
System.out.println("PARENT LOADER: " + className);
return super.loadClass(className, resolve);
}
}
public <T> Class<T> loadClass(Class<? extends T> classToLoad) throws ClassNotFoundException {
final Class<?> clazz = loadClass(classToLoad.getName());
@SuppressWarnings("unchecked")
final Class<T> castedClass = (Class<T>) clazz;
return castedClass;
}
private boolean shouldNotDelegate(String className) {
if (classesToNotDelegate.contains(className) || className.contains("tangosol") ) {
return true;
}
return false;
}
答案 0 :(得分:0)
问题1,第一部分我无法复制(见下文)。至于第2部分: 类加载器的层次结构是为了防止“X不能被强制转换为X”异常。 但如果你打破了父母优先规则,你就会遇到麻烦。
关于问题2:设置线程的上下文类加载器本身不做任何事情,另请参阅this article(javaworld.com) 更多背景知识。此外,关于问题1,第2部分,文章的引用 描述了当前类加载器之间没有父子关系会发生什么 和线程的上下文类加载器:
请记住,加载和定义类的类加载器是该类的内部JVM ID的一部分。 如果当前类加载器加载一个类X,该类随后执行,例如,对某些类型为Y的数据执行JNDI查找, 上下文加载器可以加载和定义Y. 此Y定义将与同名的定义不同,但当前加载程序可以看到。 输入晦涩的类强制转换和加载器约束违例异常。
下面是一个简单的演示程序,用于显示从另一个类加载器到接口的强制转换可以正常工作
(注意我在一个bin文件夹中使用了一个简单的Java项目,在同一个(测试)包中使用了你问题中的InvertedClassLoader
):
import java.io.File;
public class ChildFirstClassLoading {
public static void main(String[] args) {
InvertedClassLoader cl = null;
try {
File classesDir = new File(new File("./bin").getCanonicalPath());
System.out.println("Classes dir: " + classesDir);
cl = new InvertedClassLoader(classesDir.toURI().toURL());
cl.selfLoad(CTest.class);
System.out.println("InvertedClassLoader configured.");
new CTest("Test 1").test();
ITest t2 = cl.loadClass(CTest.class)
.getConstructor(String.class)
.newInstance("Test 2");
t2.test();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cl != null) {
try { cl.close(); } catch (Exception ignored) {}
}
}
}
public interface ITest {
void test();
}
public static class CTest implements ITest {
static {
System.out.println("CTest initialized.");
}
private String s;
public CTest(String s) {
this.s = s;
}
public void test() {
System.out.println(s);
}
}
}
如果您将ITest t2 =
更改为CTest t2 =
,您将获得“CTest无法转换为CTest”异常,
但使用该接口可以防止该异常。
由于这个小小的演示工作正常,我猜你的应用程序中有更多的东西会以某种方式打破类加载。
我建议你从类加载工作的情况开始工作,并继续添加代码,直到它打破了类加载。
InvertedClassLoader
看起来很像“儿童第一类加载器”,请参阅this question
对于讨论这种类加载方式的一些好答案。
子第一个类加载器可以用来分别加载“相关类”(来自你的第三个问题)。
您还可以在某些包中更新InvertedClassLoader
到始终“自加载”类。
并记住“一旦类被类加载器加载,它就使用该类加载器来加载它需要的所有其他类”
(引自this blog article)。