在web.xml中引用环境变量

40

我正在打包一个依赖于 web.xml 中某些文件路径设置的 JSP Web 应用程序。这些设置在打包时是未知的,因为它们引用了客户在部署整个应用程序(其中 Web 应用程序是管理界面)时将设置的路径。

似乎最简单的避免在我的安装脚本中使用令牌和文件修改的方法是要求用户选择安装位置,将此位置设置为环境变量(例如 JAVA_HOME),并让 web.xml 始终引用该变量。

是否有一种方法可以从 web.xml 中引用环境变量的值?谷歌搜索结果是 J2EE 方法,可以从 ejb xml 文件中设置环境变量。但这不是我想要的。


我知道你至少可以像下面这样引用HOME环境变量 ${user.home} <Connector port="8443" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="${user.home}/.keystore" keystorePass="changeit" clientAuth="false" sslProtocol="TLS"/> --> 不确定这是否有帮助,但或许可以创造性地使用它。请参阅SSL HOWTO - nsof
请查看这里所接受答案的第一个选项。通过使用来自外部文件的资源加载,只需要在类路径上可用,我认为您可以实现您想要的功能。 - gamliela
7个回答

43

您可以在任何Tomcat XML配置文件中使用Ant样式的变量替换,例如:

<servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>${foo}</url-pattern>
</servlet-mapping>

fooJava系统属性(sysprop)时。

我认为您不能直接使用操作系统环境变量(envvars)...

要使用envvars,您可以放置

set "CATALINA_OPTS=-DsomeJavaSysProp=%SOME_OS_ENVVAR%"

在bin/setenv.bat(或*nix下的bin/setenv.sh)中,您可能需要创建该文件。 Tomcat启动时将运行此文件。由于CATALINA_OPTS是环境变量(而不是命令行选项),因此其他用户在系统上不应该看到它(除了古老的Unix系统),尽管我没有测试过这一点。

http://tomcat.apache.org/tomcat-7.0-doc/config/

如果您正在使用Spring,您可以创建一个<context:property-placeholder/> bean,并直接在Spring XML配置文件中使用envvars或sysprops(但不是在web.xml中)。

我在Tomcat 7上测试过,对我来说可以工作。但它是否可移植?还是只适用于Tomcat? - mcoolive
你能详细说明如何使用property-placeholder在web.xml中使用环境变量吗? - Adam
@Adam 我认为你不能在web.xml中使用property-placeholder,只能在Spring配置XML文件中使用。 - Neil McGuigan
我明白了。那么,如果我选择您的第一个解决方案并创建一个bash脚本来设置Java系统属性,我需要做些什么来确保spring/tomcat运行该脚本吗? - Adam
@Adam 如果你使用Tomcat的setenv批处理文件,它将在Tomcat启动时自动运行。 - Neil McGuigan

13

我认为你不想使用环境变量(我认为从web.xml中无法访问),但可以使用环境条目 [1, 2]。如下:

<env-entry>
    <env-entry-name>Bla/SomeFilePath</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>/opt/bla</env-entry-value>
</env-entry>

您可以像这样使用SomeFilePath:

InitialContext ic = new InitialContext();
String s = (String) ic.lookup("java:comp/env/ejb/Bla/SomeFilePath");

1
问题是,这个Web应用程序是生成的代码,我不想去乱改它,除了在web.xml中更改特定变量的值。因此,我正在寻找一种方法来设置仅引用预设环境变量的方式来设置该值。 - Udi Bar-On
就像我说的那样:我认为在部署描述符中使用环境变量是不可能的。恐怕没有绕过更改一些代码的方法。 - ax.

9

基本上,你不应该这样做。 web.xml 应该包含默认值,但是在实际部署时应该覆盖它们。如果你要部署到 Tomcat,可以通过在用于部署的 context.xml 中包含适当的条目来实现。例如:

<Context path="/app">
    <!-- For things described by webapp parameters -->
    <Parameter name="foobar" value="grill" />

    <!-- For things described by environment entries -->
    <Environment name="Bla/SomeFilePath" type="java.lang.String"
            value="/opt/bla" />
</Context>

其他容器将有自己的机制来完成这个过程。您需要查阅它们的文档(或更加专注地寻求帮助)。


6

环境变量可以像这样在xml文件中访问:

${env.ENVIRONMENT_VARIABLE_NAME}

显然,用户账户设置和访问问题可能会存在一些问题,但我已经尝试了使用系统变量,它可以正常工作!


这是JEE标准还是只是自定义应用程序服务器支持? - Simon Logic

1
你必须按顺序放置env-entry:
<env-entry>
  <env-entry-name>maxAmount</env-entry-name>
  <env-entry-type>java.lang.String</env-entry-type>
  <env-entry-value>aString</env-entry-value>
</env-entry>

否则,您将在web.xml上遇到验证错误。 参考:https://community.oracle.com/thread/840452?tstart=0

你引发了一个递归问题:如何将真实的环境变量放入env-entry-value中。 - Simon Logic

1
我不完全了解你的限制,但也许你可以这样做(我假设你正在尝试配置init-param): 1)在web.xml中未指定变量 2)创建一个ServletContextListener并将其添加到您的应用程序中 3)监听您的servlet的初始化 4)在此时为servlet设置初始参数
我曾经尝试过类似的问题,但失败了,因为结果表明第三方servlet(我也不想搞砸它)根本没有像servlet一样运行,因此上下文从未被初始化。但也许这里有机会...

0
如果您正在使用Spring,您可以通过ConfigurableBeanFactory.resolveEmbeddedValueFilterConfig传递来启用web.xml中的属性占位符插值支持。
代理类可使FilterConfig参数可解析。
public class ResolvableFilterConfig implements FilterConfig {

    private final FilterConfig source;
    private final ConfigurableBeanFactory resolver;

    public ResolvableFilterConfig(FilterConfig source, ConfigurableBeanFactory resolver) {
        this.source = source;
        this.resolver = resolver;
    }

    @Override
    public String getFilterName() {
        return source.getFilterName();
    }

    @Override
    public ServletContext getServletContext() {
        return source.getServletContext();
    }

    @Override
    public String getInitParameter(String name) {
        final String value = source.getInitParameter(name);
        return resolver.resolveEmbeddedValue(value);
    }

    @Override
    public Enumeration<String> getInitParameterNames() {
        return source.getInitParameterNames();
    }
}

过滤器实现示例代码

    @Override
    public void init(FilterConfig config) throws ServletException {
        // configure
        final ServletContext servletContext = config.getServletContext();
        final AbstractApplicationContext aac = (AbstractApplicationContext) getRequiredWebApplicationContext(servletContext);
        final ConfigurableBeanFactory beanFactory = aac.getBeanFactory();
        config = new ResolvableFilterConfig(config, beanFactory);
        // ... do the rest
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接