任务和初步调查
我尝试在一个 java swing 应用程序的缓存实例附近设置两个 Oracle Coherence。可以在这里找到解决方案的想法。我的情况有点复杂,这就是游戏开始的地方。
简短的介绍
就我而言,有一个帐户服务。它可以有两个端点:SIT 和 UAT。为了创建两个这样的服务,我需要加载 Coherence 的两个“实例”,以便用系统变量 ( tangosol.coherence.cacheconfig ) 覆盖端点。
我有:
- 应用程序的主要代码位于 mainapp.jar 中;
- 位于 account-interfaces.jar 中的AccountService接口;
- 位于 account-impl.jar 中并实现AccountService接口的AccountServiceImpl类;
- 我的主要应用程序具有以下结构
bin: startup.bat, startup.sh conf: app.properties lib: mainapp.jar, account-interfaces.jar, account-impl.jar, coherence.jar
尝试的方法
我创建了一个专用的子类加载器 - InverseClassLoader,并将 AppLaunchClassLoader(默认的 Thread.currentThread().GetContextClassLoader() 类加载器)设为父级。使用 InverseClassLoader 我加载 AccountServiceImpl 类:
Class<AccountServiceImpl> acImplClass = contextClassLoader.selfLoad(AccountServiceImpl.class).loadClass(AccountServiceImpl.class);
Constructor<AccountServiceImpl> acConstructor =
acImplClass .getConstructor(String.class);
AccountService acService = acConstructor .newInstance(serviceURL);
问题和疑问
- 我得到“AccountServiceImpl 无法转换为 AccountService”异常,这意味着这两个类由不同的类加载器加载。但是那些类加载器是父子关系。所以即使一个类是由父类(接口 - '抽象'类型)加载的,它也不能与子类加载器加载的类(具体 impl)一起使用,这对吗?那么为什么我们需要这种父子关系呢?
- 我在代码中指定了 AccountService 接口,它由默认的类加载器加载。我尝试将上面的代码包装为一个线程并将 InverseClassLoader 设置为上下文类加载器。没有改变。那么我不能使用这样的接口实现编码(如通常的编码)并且需要一直使用反射来调用具体方法是对的吗?(希望有解决方案);
- 比如说,我列出了由 InverseClassLoader 加载的 AccountService 和 AccountServiceImpl 类。如果我需要这两个可以访问的其他类也由 InverseClassLoader 加载怎么办?有没有办法说所有“相关”类必须由同一个类加载器加载?
更新
这是 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;
}