看看 org.hibernate.internal.util.ClassLoaderHelper。
您所要做的就是用能够解析实体类的 ClassLoader 替换 ClassLoader。Hibernate-Osgi 也将其设置为 OSGI ClassLoader(参见 org.hibernate.osgi.HibernateBundleActivator)。所以建议如下:
BundleWideClassLoader cl = new BundleWideClassLoader();
if (ClassLoaderHelper.overridenClassLoader != null
&& ClassLoaderHelper.overridenClassLoader instanceof OsgiClassLoader)
{
OsgiClassLoader ocl = (OsgiClassLoader)ClassLoaderHelper.overridenClassLoader;
for (Bundle b : cl.getBundles()) {
ocl.addBundle(b);
}
} else {
ClassLoaderHelper.overridenClassLoader = new BundleWideClassLoader();
}
我通过覆盖执行此例程并返回 super.buildSessionFactory 的 buildSessionFactory 将它放到我的 HibernateConfiguration 类中。
BundleWideClassLoader 看起来像这样
public class BundleWideClassLoader extends ClassLoader
{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
for (BundleClassLoader cl : this.getAllClassLoader()) {
try {
Class clazz = cl.findClass(name);
return clazz;
} catch (Exception ex) {
}
}
throw new ClassNotFoundException(name);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class clazz = this.findClass(name);
if (resolve) {
this.resolveClass(clazz);
}
return clazz;
}
@Override
public URL findResource(String name) {
for (BundleClassLoader cl : this.getAllClassLoader()) {
URL ret = cl.findResource(name);
if (ret != null) {
return ret;
}
}
return null;
}
/**
* Returns a list of all available BundleClassLoader.
*
* @return classloader
*/
public HashSet<BundleClassLoader> getAllClassLoader() {
//
// Do some magic here to get your ClassLoaders from all of your Bundles
//
}
/**
* Returns a list of all bundles which are registered in this BundleWideClassLoader.
*
* @return list of managed bundles
*/
public HashSet<Bundle> getBundles() {
HashSet<Bundle> bundles = new HashSet<>();
for (BundleClassLoader cl : this.getAllClassLoader()) {
bundles.add(cl.getBundleContext().getBundle());
}
return bundles;
}
}
最后是 BundleClassLoader:
public class BundleClassLoader extends ClassLoader
{
/**
* Bundle context.
*/
private BundleContext context;
/**
* Constructor.
* @param ctx Bundle Context
*/
public BundleClassLoader(BundleContext ctx) {
this.context = ctx;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return this.context.getBundle().loadClass(name);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class clazz = this.findClass(name);
if (resolve) {
this.resolveClass(clazz);
}
return clazz;
}
@Override
public URL findResource(String name) {
return this.context.getBundle().getResource(name);
}
/**
* Returns bundle context.
* @return bundle context
*/
public BundleContext getBundleContext() {
return this.context;
}
}
我建议在每个 BundleActivators 中创建一个新的 BundleClassLoader 并将其添加到某种注册表中,以便 BundleWideClassLoader 可以从那里获取 BundleClassLoader 列表。当捆绑停止或删除时,不要忘记删除 BundleClassLoader。