OSGI类加载器无法在捆绑中看到JPA实体

问题描述 投票:0回答:3

我是OSGi环境的新手,也许我想念一些东西。我无法加载OSGI包中包含的JPA实体(ClassNotFoundException)。

我正在使用Apache Felix和Hibernate。我没有使用蓝图。

这是我的架构:

  • 应用A:通用接口。对此没什么好说的。
  • 应用程序B:是WebApp。它在启动Host bundle的启动时启动felix框架。主机Host包安装特定文件夹中包含的所有bundle的jar并跟踪服务(在Application C中实现的服务)。它有应用程序A作为依赖。
  • 应用程序C:它是客户端包。它实现了Application A接口并对其进行了注册(它将App A作为依赖项)。它还包含我在此捆绑包中需要的所有JPA模型。

我遇到的问题是在应用程序C实现中:它配置运行时org.hibernate.cfg.Configuration和load是自己的JPA模型(cfg.addAnnotatedClass(EntityTest.class))。此时我得到了这个例外:

org.hibernate.AssertionFailure:PersistentClass名称无法转换为org.hibernate.cfg.BinderHelper.getPropertyOverriddenByMapperOrMapsId(BinderHelper.java:877)中的org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2179)中的org .hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:925)...

这是由

引起:org.hibernate.annotations.common.reflection.ClassLoadingException:无法在org.hibernate.annotations.common.util.StandardClassLoaderDelegateImpl.classForName(StandardClassLoaderDelegateImpl.java:60)加载Class [com.osgi.bundle1.model.EntityTest] )org.hibernate的org.hibernate.boot.internal.MetadataBuilderImpl $ MetadataBuildingOptionsImpl $ 4.classForName(MetadataBuilderImpl.java:758)org.hibernate的org.hibernate.annotations.common.reflection.java.JavaReflectionManager.classForName(JavaReflectionManager.java:144) .cfg.BinderHelper.getPropertyOverriddenByMapperOrMapsId(BinderHelper.java:874)... 58常见的帧省略由以下原因引起:java.lang.ClassNotFoundException:com.osgi.bundle1.model.EntityTest at org.apache.catalina.loader.WebappClassLoaderBase.loadClass (webappClassLoaderBase.java:1333)位于java.lang.Class.forName(Class.java)java.lang.Class.forName0(Native Method)的org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1167) :348)org.hibernate .annotations.common.util.StandardClassLoaderDelegateImpl.classForName(StandardClassLoaderDelegateImpl.java:57)...省略了61个常用帧

应用程序C已经导出模型,我使用了https://docs.gradle.org/current/userguide/osgi_plugin.html

编辑:添加更多细节。

应用程序B是使用Jersey构建的webapp。它有一个启动felix的ServletContextListener:

@WebListener
public class Felixbootstrap implements ServletContextListener{

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        OsgiHost.initialize();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}


 public class OsgiHost {  

    public static void initialize() {
        OsgiHost host = new OsgiHost();
        host.start();
    }

    private void start() {
        Map<String, Object> config = new HashMap<>();

        config.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, Arrays.asList(
                , new HostBundle()//Activator that starts bundles of the project
        ));

        config.put(FelixConstants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);

        //package to export
        String felixPackageExportConfiguration =
                //common api
                "com.osgi.test.api"
                        + ",com.osgi.test.dto"
                        //hibernate
                        + ",javax.persistence;version=2.1.0"
                        + ",org.hibernate"
                        + ",org.hibernate.cfg"
                        + ",javassist.util.proxy"
                        + ",org.hibernate.proxy"
                        + ",org.hibernate.query"
                ;

        config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, felixPackageExportConfiguration);

        Felix felix = new Felix(config);
        try {
            felix.start();
        } catch (BundleException e) {
            e.printStackTrace();
        }
    }
 }

应用程序C有一个由应用程序B上的端点调用的方法(通过公共接口)。当它被调用时,这个类被初始化(总是在应用程序C中):

public class HibernateUtil {

   private SessionFactory sf;
   private static HibernateUtil instance = null;

   public static HibernateUtil getInstance() {
        if (instance == null) {
            instance = new HibernateUtil();
        }
        return instance;
    }

    private HibernateUtil() {
    }

    public Session getSession() {
        return getSessionFactory().openSession();
    }

    private SessionFactory getSessionFactory() {
        if (sf == null) {

            Configuration cfg = new Configuration();
            cfg.addAnnotatedClass(EntityTest.class);

            cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL94Dialect")
                    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/jdbcname")
                    .setProperty("hibernate.ejb.naming_strategy", "org.hibernate.cfg.DefaultNamingStrategy")
                    .setProperty("hibernate.archive.autodetection", "class")
                    .setProperty("hibernate.hbm2ddl.auto", "update")
            ;
            sf = cfg.buildSessionFactory();

        }
        return sf;
    }
}
hibernate jpa osgi apache-felix
3个回答
1
投票

这根本不像OSGi问题。堆栈跟踪表明Hibernate正在尝试从Web Application类加载器加载模型类,即部署在Tomcat上的WAR文件(Apache Catalina是实现Servlet规范的Tomcat的一部分)。

此WAR文件的WEB-INF/classes目录或WEB-INF/lib下的某个JAR文件中是否包含相关的类?


1
投票

从代码段:

    //package to export
    String felixPackageExportConfiguration =
            //common api
            "com.osgi.test.api"
                    + ",com.osgi.test.dto"
                    //hibernate
                    + ",javax.persistence;version=2.1.0"
                    + ",org.hibernate"
                    + ",org.hibernate.cfg"
                    + ",javassist.util.proxy"
                    + ",org.hibernate.proxy"
                    + ",org.hibernate.query"
            ;

    config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, felixPackageExportConfiguration);

它看起来非常像Hibernate在OSGi框架之外。虽然您使用的命名方案不明确,但听起来好像您的JPA实体位于OSGi包中的OSGi框架内。

然后,您引导Hibernate的方式是使用专为在平坦的Java SE类路径中使用而设计的API。没有理由期望Hibernate能够找到你的实体类型,因为Hibernate可以访问的ClassLoader没有对OSGi框架的可见性。

回到更高的层次 - 通过使用OSGi框架,您试图实现的目标是什么?如果你想使用OSGi进行数据访问,那么为什么Hibernate不能在OSGi框架内运行,因为它有机会看到实体类?

在你可以使用的OSGi框架中有一个使用JPA的标准,但是我觉得这个应用程序还有很多其他的东西你还没有告诉我们 - 例如,没有代码显示请求如何进入OSGi框架,也没有任何代码显示框架是如何停止的......


0
投票

蒂姆很可能是现货。 Hibernate ORM必须以三种支持的方式之一进行引导。我们的文档遍历所有这些,看起来您可能对“非托管本机”模式最感兴趣。简而言之,除非您使用Apache Aries之类的东西来发现您的持久性单元并为您启动内容,否则您需要手动执行此操作。

https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/osgi/OSGi.html

© www.soinside.com 2019 - 2024. All rights reserved.