Java Hibernate具有运行时POJO的OSGi片段包

Java Hibernate具有运行时POJO的OSGi片段包,java,hibernate,osgi,Java,Hibernate,Osgi,我的要求是使用hibernate映射各种数据库(特别是SQL Server、MySQl和Postgres);从db记录创建一个xml文件 对于hibernate,我在运行时使用JAssist创建hbm文件和POJO。 我的代码工作得很好,为了进一步模块化,我为每个数据库实现了片段捆绑包。这样,我的主机捆绑包将处理运行时类的创建,并将它们添加到classloader、hbm文件创建逻辑和BL中。fragment通过传递参数来调用它 当我为每个数据库创建一个片段包时, 在主机包中创建的运行时pojo

我的要求是使用hibernate映射各种数据库(特别是SQL Server、MySQl和Postgres);从db记录创建一个xml文件

对于hibernate,我在运行时使用JAssist创建hbm文件和POJO。 我的代码工作得很好,为了进一步模块化,我为每个数据库实现了片段捆绑包。这样,我的主机捆绑包将处理运行时类的创建,并将它们添加到classloader、hbm文件创建逻辑和BL中。fragment通过传递参数来调用它

当我为每个数据库创建一个片段包时, 在主机包中创建的运行时pojo类在片段包中可见, 我检查了“Thread.currentThread().getContextClassLoader().loadClass()” 并能够创建其实例

问题是 当我从fragment bundle调用Hibernate函数时,我得到的是“Entity not mapping”,当Hibernate无法找到带有表的映射类时,会出现这些异常。 所以我想Hibernate没有找到我的运行时pojo类。它可以在主机中找到

主持人: 运行时Pojo创建, HBM和CFG创建和更新逻辑 基本法

片段: 冬眠层, 调用Hibernate函数,
XML创建逻辑

如果在多个捆绑包上使用Hibernate,则始终会出现此问题。在Hibernate配置中,您无法分辨在哪个包中可以找到映射文件和pojo类文件。Hibernate不使用OSGI为此提供的机制。因此,hibernate仅查找与hibernate库位于同一捆绑包中的映射文件和类

我不知道是否有专业的解决方案(第三方产品)来解决这个问题

解决此问题有两种可能性:

  • 忘记片段捆绑包,将所有数据库的所有Hibernate库、映射文件、POJO和使用Hibernate/HQL的类放在一个捆绑包中。当您使用不同的hibernate.cfg.xml文件时,可以在不同的数据库之间切换;每个数据库都有自己的配置文件。这些hibernate.cfg.xml文件可以位于捆绑包之外

  • 编写您自己的配置类,扩展org.hibernate.cfg.Configuration,在这个类中您必须

    • 编写自己的类加载器,即使在其他包中也能找到pojo类
    • 重写addResource(String resourceName,ClassLoader ClassLoader),以使其也能在其他捆绑包中找到资源
    • 重写doConfigure和buildSessionFactory,以便它们使用您的类加载器而不是标准类加载器(使用Thread.setContextClassLoader并从超类(即标准Hibernate配置类)调用该方法)
    • 重写所有其他返回配置实例的方法,以便它们返回配置类的实例,而不是Hibernate配置类的实例

  • 我们完成了解决方案2。这是一点工作,但现在运行良好。(我想,当再次更改Hibernate版本时,可能需要做一些工作。)

    查看org.Hibernate.internal.util.ClassLoaderHelper

    您所要做的就是用能够解析实体类的类加载器替换类加载器。 Hibernate Osgi还将其设置为Osgi类加载器(请参见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();
    }
    
    我通过重写buildSessionFactory将其放入HibernateConfiguration类,该类执行此例程并返回super.buildSessionFactory

    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;
    }
    
    }
    
    公共类BundleWideClassLoader扩展了ClassLoader
    {
    @凌驾
    受保护类findClass(字符串名称)引发ClassNotFoundException{
    对于(BundleClassLoader cl:this.getAllClassLoader()){
    试一试{
    类clazz=cl.findClass(名称);
    回击声;
    }捕获(例外情况除外){
    }
    }
    抛出新的ClassNotFoundException(名称);
    }
    @凌驾
    受保护类loadClass(字符串名称,布尔解析)引发ClassNotFoundException{
    Class clazz=this.findClass(名称);
    如果(解决){
    这个类(clazz);
    }
    回击声;
    }
    @凌驾
    公共URL findResource(字符串名称){
    对于(BundleClassLoader cl:this.getAllClassLoader()){
    URL ret=cl.findResource(名称);
    如果(ret!=null){
    返回ret;
    }
    }
    返回null;
    }
    /**
    *返回所有可用BundleClassLoader的列表。
    *
    *@returnclassloader
    */
    公共HashSet getAllClassLoader(){
    //
    //在这里做一些魔术,从你所有的包中获得你的类加载器
    //
    }
    /**
    *返回在此BundleWideClassLoader中注册的所有捆绑包的列表。
    *
    *@托管捆绑包的返回列表
    */
    公共HashSet getBundles(){
    HashSet bundles=新的HashSet();
    对于(BundleClassLoader cl:this.getAllClassLoader()){
    bundles.add(cl.getBundleContext().getBundle());
    }
    返回包;
    }
    }
    
    最后是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;
    }
    
    }
    
    公共类BundleClassLoader扩展了ClassLoader
    {
    /**
    *捆绑上下文。
    */
    私密文本语境;
    /**
    *构造器。
    *@param ctx Bundle上下文
    */
    公共BundleClassLoader(BundleContext ctx){
    this.context=ctx;
    }
    @凌驾
    受保护类findClass(字符串名称)引发ClassNotFoundException{
    返回此.context.getBundle().loadClass(名称);
    }
    @凌驾
    受保护类loadClass(字符串名称,布尔解析)引发ClassNotFoundException{
    Class clazz=this.findClass(名称);
    如果(解决){
    这个类(clazz);
    }
    回击声;
    }
    @凌驾
    公共URL findResource(字符串名称){
    返回此.context.getBundle().getResource(名称);
    }
    /**
    *返回绑定上下文。
    *@returnbundle上下文
    */
    public BundleContext getBundleContext(){
    返回这个.context;
    }
    }
    
    我建议在每个外滩都创建一个新的BundleClassLoader