OSGI类加载器无法在包

时间:2017-12-18 09:32:27

标签: hibernate jpa osgi apache-felix

我是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名称不能   转换成一个类           at 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:无法加载类[com.osgi.bundle1.model.EntityTest]           在org.hibernate.annotations.common.util.StandardClassLoaderDelegateImpl.classForName(StandardClassLoaderDelegateImpl.java:60)           at org.hibernate.boot.internal.MetadataBuilderImpl $ MetadataBuildingOptionsImpl $ 4.classForName(MetadataBuilderImpl.java:758)           在org.hibernate.annotations.common.reflection.java.JavaReflectionManager.classForName(JavaReflectionManager.java:144)           at org.hibernate.cfg.BinderHelper.getPropertyOverriddenByMapperOrMapsId(BinderHelper.java:874)           ...省略了58个常用帧   引起:java.lang.ClassNotFoundException:com.osgi.bundle1.model.EntityTest           在org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1333)           在org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1167)           at java.lang.Class.forName0(Native Method)           在java.lang.Class.forName(Class.java:348)           at org.hibernate.annotations.common.util.StandardClassLoaderDelegateImpl.classForName(StandardClassLoaderDelegateImpl.java:57)           ...省略了61个常见帧

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

编辑添加了更多详细信息。

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

@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;
    }
}

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分: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框架,也没有任何代码显示框架是如何停止的......

答案 2 :(得分:0)

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

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