为什么Java扩展机制不检查实现LocaleServiceProvider的可选包的类路径? [英] Why does the Java Extension Mechanism not check the classpath for an optional package implementing LocaleServiceProvider?

查看:184
本文介绍了为什么Java扩展机制不检查实现LocaleServiceProvider的可选包的类路径?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个maven项目L,并编写了 Java扩展(即可选包)实现(即扩展)实现(即扩展)

  • 类路径:类,包括JAR文件中的类, 在系统属性java.class.path指定的路径上.如果是JAR 类路径上的文件具有带有Class-Path属性的清单, 由Class-Path属性指定的JAR文件也将被搜索. 默认情况下,java.class.path属性的值为.,当前 目录.您可以使用-classpath或-cp来更改值 命令行选项,或设置CLASSPATH环境变量. 命令行选项将覆盖CLASSPATH的设置 环境变量.
  • 我相信,Maven会将所有依赖项放在类路径上.

    但是,当我在P中运行单元测试(在IntelliJ中; L在类路径上)时,它失败:

    @Test
    public void xyLocalePresent() {
        Locale xy = new Locale("xy");
        assertEquals("P not on classpath", xy, com.example.l.Locales.XY); // access constant in my Locale project L; should be equals to locale defined here
        SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, xy);
        assertEquals("dd/MM/yy", df.toPattern()); // fails; L specifies the short date pattern as dd/MM/yy
    }
    

    我必须从-Djava.locale.providers=SPI,JRE -Djava.ext.dirs=/path/to/project/L/target开始.如果我这样做,它会起作用,表明L的服务提供程序已成功加载(表明jar的结构正常).

    NB:Java 8 technotes 说默认的订单SPI,JRE.

    为什么,当我将L放在类路径上时,为什么它不起作用?为什么我必须明确指出它?

    更新:在再次阅读JavaDoc之后,我刚刚看到了这一点(强调我的意思):

    这些对语言环境敏感的服务的实现打包为 Java扩展机制作为已安装扩展.

    这说明了事情. :(

    有什么方法可以通过在运行P时将L放在类路径上来实现此目的,即无需安装L (或必须使用-D系统属性)? (P使用maven,Struts2和Spring,如果有帮助的话...)

    解决方案

    在诸如Web服务器(例如Tomcat)之类的更复杂的应用程序中,有多个ClassLoader,因此可以将由Web服务器提供服务的每个WebApp保持独立. /p>

    扩展机制用于扩展核心Java功能,即正在运行的JVM(Web服务器)中全局可用的功能.因此,它们必须由System ClassLoader加载.

    向代码Java运行时添加扩展的标准方法是

    • 将Jar文件添加到JRE_HOME/lib/ext文件夹
    • 通过指定java.ext.dirs系统属性添加其他要搜索的文件夹

    您也可以自己将其添加到Bootstrap ClassPath中,但是如果激活了安全管理器,则可能会导致问题.不确定那部分.因此,最好以正式方式进行操作.

    请注意,由CLASSPATH环境变量或-cp命令行选项定义的类路径未定义Bootstrap ClassPath.

    要了解更多信息,请阅读Java文档"如何分类找到".

    I have created a maven project L and written a Java extension (i.e. an optional package) implementing (i.e. extending) the (abstract) service providers that implement (i.e. extend) LocaleServiceProvider, to support a dialect (let's call it xy) that isn't normally supported by the JRE. (I do not want to use the CLDR extension that came with Java 8, even though I'm running 8.141.)

    The project compiles, and produces a jar with a META-INF/services folder that contains the provider-configuration files in UTF-8 with the qualified provider class names being on a line that ends with a line feed (\n).

    I have then declared a maven dependency in my project P on the locale project L, and I thought that that would work, because the tutorial states

    The extension framework makes use of the class-loading delegation mechanism. When the runtime environment needs to load a new class for an application, it looks for the class in the following locations, in order:

    [...]

    1. The class path: classes, including classes in JAR files, on paths specified by the system property java.class.path. If a JAR file on the class path has a manifest with the Class-Path attribute, JAR files specified by the Class-Path attribute will be searched also. By default, the java.class.path property's value is ., the current directory. You can change the value by using the -classpath or -cp command-line options, or setting the CLASSPATH environment variable. The command-line options override the setting of the CLASSPATH environment variable.

    Maven puts all dependencies on the classpath, I believe.

    Yet when I run my unit test in P (in IntelliJ; L is on the classpath), it fails:

    @Test
    public void xyLocalePresent() {
        Locale xy = new Locale("xy");
        assertEquals("P not on classpath", xy, com.example.l.Locales.XY); // access constant in my Locale project L; should be equals to locale defined here
        SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, xy);
        assertEquals("dd/MM/yy", df.toPattern()); // fails; L specifies the short date pattern as dd/MM/yy
    }
    

    I have to start it with -Djava.locale.providers=SPI,JRE -Djava.ext.dirs=/path/to/project/L/target. If I do that, it works, indicating that L's service providers were loaded successfully (indicating the jar's structure is ok).

    NB: the Java 8 technotes say that the order SPI,JRE is the default.

    Why, oh why does it not work when I just put L on the classpath? Why do I have to point to it explicitly?

    Update: After going through the JavaDoc again, I just saw this (emphasis mine):

    Implementations of these locale sensitive services are packaged using the Java Extension Mechanism as installed extensions.

    That explains things. :(

    Is there any way to make this work by just putting L on the classpath when P runs, i.e. without having to install L (or having to use -D system properties)? (P uses maven, Struts2 and Spring, if that helps...)

    解决方案

    In more complex applications, such as web servers (e.g. Tomcat), there are multiple ClassLoaders, so each WebApp served by the web server can be kept independent.

    The extension mechanism is for extending the core Java functionality, i.e. features available globally within the running JVM (the web server). As such, they must be loaded by the System ClassLoader.

    The standard way to add an extension to the code Java runtime, is to either

    • add the Jar file to the JRE_HOME/lib/ext folder
    • add extra folders to be searched by specifying the java.ext.dirs system property

    You could also just add it to the Bootstrap ClassPath yourself, but that might cause problems if the Security Manager is activated. Not sure about that part. So it's best to do it the official way.

    Note that the classpath defined by the CLASSPATH environment variable, or the -cp command-line option, does not define the Bootstrap ClassPath.

    To learn more, read the Java documentation "How Classes are Found".

    这篇关于为什么Java扩展机制不检查实现LocaleServiceProvider的可选包的类路径?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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