如何在JBoss 5.x上使用JPA2? (或如何消除类加载隔离问题?) [英] How to use JPA2 on JBoss 5.x ? (or How to eliminate class loading isolation issue?)

查看:80
本文介绍了如何在JBoss 5.x上使用JPA2? (或如何消除类加载隔离问题?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望JBoss只使用我的war文件中的依赖项。
每次我部署这个war文件时,JBoss仍然使用自己的jar。

I would like JBoss to use only the dependencies located in my war file. Each time I deploy this war file, JBoss still uses its own jars.

这是 jboss-web.xml 我使用:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <class-loading java2ClassLoadingCompliance="false">
        <loader-repository>
            my.package:loader=my-app.war
           <loader-repository-config>
              java2ParentDelegation=false
           </loader-repository-config>
        </loader-repository>
    </class-loading>
</jboss-web>

jboss-classloading.xml

<?xml version="1.0" encoding="UTF-8"?>
<classloading 
    xmlns="urn:jboss:classloading:1.0"
    export-all="NON_EMPTY"
    import-all="true"
    parent-first="false"/>

JBoss 5.1.0.GA

推荐答案

1>摘要

最初,我试过这个类加载用于加载带有JBoss 5.1.0.GA的Hibernate 3.6.4 jar的隔离。

Initially, I have tried this class loading isolation for loading Hibernate 3.6.4 jars with JBoss 5.1.0.GA.

这绝对不可能。引擎盖下有一些魔力这会阻止你使用任何支持JPA2的Hibernate版本。

It's definitively NOT possible. There is some magic under the hood that prevents you from using any Hibernate version with JPA2 support.

我真的失望 JBoss项目没有提供某种补丁或用于在5.1.0.GA上支持JPA2的服务包。


I'm really disappointed that JBoss project didn't provide some kind of patch or service pack for supporting JPA2 on 5.1.0.GA.

2>替代方法 内核解决方案

我已经设法使用JPA2和JBoss 5.1.0.GA
我在这里描述我的食谱。它可以用来制作自己的解决方案。

2> WORKAROUND : "The Kernel solution"
I have managed to use JPA2 with JBoss 5.1.0.GA I describe here my recipe. It's more a proof of concept you can use to make your own solution.

成分:


  • 1 WAR存档

  • 1 servlet

  • 1个独立的Java应用程序(J2SE)

食谱:

第1步:构建独立应用程序(APP)

Step 1: Build the standalone application (APP)

此应用程序将从servlet接收使用Hibernate的指令。

This application will receive instructions from the servlet for using Hibernate.

我给你留下通讯方式的选择。
由于APP使用JPA2,它需要一个位于 META-INF 中的 persistence.xml 文件夹。
从JBoss 5.x开始,当您部署WAR时,JBoss将扫描WAR及其所有子部署,以便盲目地查找和部署 persistence.xml 文件。例如,将 persistence.xml 文件重命名为 my-persistence.xml 。在构建 EntityManagerFactory 时使用以下代码(防止JBoss部署persistence.xml)。

I leave you the choice of the communication method. As the APP uses JPA2, it will need a persistence.xml file located in a META-INF folder. Since JBoss 5.x, when you deploy a WAR, JBoss will scan the WAR and all its sub-deployments for finding and deploying blindly persistence.xml files. Rename your persistence.xml file into my-persistence.xml for example. Use the code below when you build your EntityManagerFactory (Prevent JBoss from deploying persistence.xml).

更新:
这个方法确实有效,但Hibernate引发了一些奇怪的警告。为了阻止这些警告,我决定将 META-INF 文件夹和持久性文件(重命名为 persistence.xml now。在我的例子中,我在硬盘驱动器上选择了一个特殊的配置文件夹,并将其添加到类路径中。没有更奇怪的警告,也没有加载持久性文件所需的自定义类加载器。

UPDATE: This method does work but some strange warnings are raised by Hibernate. In order to stop those warnings, I have decided to put the META-INF folder and the persistence file (renamed back to persistence.xml now) outside of the WAR. In my case, I choosed a special config folder on the hard drive and added it to the classpath. No more strange warnings and no custom classloader required for loading the persistence file.

我让你在使用自定义类加载器或更改持久性文件位置之间做出选择。在这两种情况下,JBoss都找不到持久性文件。




第2步:构建servlet

I leave it up to you to choose between using a custom class loader or changing the persistence file location. In both cases, JBoss won't find the persistence file.


Step 2: Build the servlet

当servlet需要时访问数据库,它启动APP并告诉它该做什么。

When the servlet needs to access the database, it launches the APP and tells it what to do.

为了推动APP,servlet负责产生一个新的JVM并构建它的类路径。 APP。阅读下面的代码(生成JVM)。类路径很容易可构建,因为所有必需的jar都位于WAR存档的 / lib 目录中...




第3步:构建WAR存档

For lauching the APP, the servlet is responsible of spawning a new JVM and build the classpath of the APP. Read the code below for (Spawning a JVM). The classpath is easily buildable since all the required jars will be in the /lib directory of the WAR archive...


Step 3: Build the WAR archive

构建一个WAR存档,放置servlet和独立应用程序打包为JAR。 APP将是WAR的依赖。

Build a WAR archive where you put the servlet and the standalone application packaged as a JAR. The APP will be a dependency of the WAR.

防止JBoss部署persistence.xml

// Install a proxy class loader for adding renamed persistence.xml file
Thread t = Thread.currentThread();
ClassLoader clOriginal = t.getContextClassLoader();
t.setContextClassLoader(new SpecialClassLoader(clOriginal, "META-INF/my-persistence.xml"));

// Build EntityManagerFactory
EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);

// Restore original class loader
t.setContextClassLoader(clOriginal);

//...

private class ProxyClassLoader extends ClassLoader {
    private ClassLoader realClassLoader;
    private String hiddenFromJBossPersistenceFile;

    public ProxyClassLoader(ClassLoader realClassLoader, String hiddenFromJBossPersistenceFile) {
        this.realClassLoader = realClassLoader;
        this.hiddenFromJBossPersistenceFile = hiddenFromJBossPersistenceFile;
    }

    public void clearAssertionStatus() {
        realClassLoader.clearAssertionStatus();
    }

    public boolean equals(Object obj) {
        return realClassLoader.equals(obj);
    }

    public URL getResource(String name) {
        return realClassLoader.getResource(name);
    }

    public InputStream getResourceAsStream(String name) {
        return realClassLoader.getResourceAsStream(name);
    }

    public Enumeration<URL> getResources(String name) throws IOException {
        ArrayList<URL> resources = new ArrayList<URL>();

        if (name.equalsIgnoreCase("META-INF/persistence.xml")) {
            resources.add(getResource(this.hiddenFromJBossPersistenceFile));
        }
        resources.addAll(Collections.list(realClassLoader.getResources(name)));

        return Collections.enumeration(resources);
    }

    public int hashCode() {
        return realClassLoader.hashCode();
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return realClassLoader.loadClass(name);
    }

    public void setClassAssertionStatus(String className, boolean enabled) {
        realClassLoader.setClassAssertionStatus(className, enabled);
    }

    public void setDefaultAssertionStatus(boolean enabled) {
        realClassLoader.setDefaultAssertionStatus(enabled);
    }

    public void setPackageAssertionStatus(String packageName, boolean enabled) {
        realClassLoader.setPackageAssertionStatus(packageName, enabled);
    }

    public String toString() {
        return realClassLoader.toString();
    }
}

产生JVM

public static Process createProcess(final String optionsAsString, final String workingDir, final String mainClass, final String[] arguments) throws IOException {
    String jvm = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";

    String[] options = optionsAsString.split(" ");
    List<String> command = new ArrayList<String>();
    command.add(jvm);
    command.addAll(Arrays.asList(options));
    command.add(mainClass);
    command.addAll(Arrays.asList(arguments));

    //System.out.println(command);

    ProcessBuilder processBuilder = new ProcessBuilder(command);
    processBuilder.directory(new File(workingDir));

    return processBuilder.start();
}

public static void makeItRun() {
   try {
      // Start JVM
      String classPath = buildClassPath();
      String workingDir = getSuitableWorkingDir();//or just "."
      Process java = createProcess("-cp \"" + classPath + "\"", workingDir, my.package.APP.class.getCanonicalName(), "-the -options -of -my -APP");

      // Communicate with your APP here ...

      // Stop JVM
      java.destroy();
   } catch(Throwable t) {
      t.printStackTrace();
   }
}

这篇关于如何在JBoss 5.x上使用JPA2? (或如何消除类加载隔离问题?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆