您应该在server.xml还是context.xml中设置数据库连接属性


79

我正在尝试使用JNDI为Spring Web应用程序设置数据库连接属性。

我正在考虑以下两种方法:

方法1:

在您的Spring配置中,您可能会有类似以下内容:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/facs"/>

然后,在您的webapp /META-INF/context.xml文件中,您也应该具有类似的内容:

<?xml version='1.0' encoding='utf-8'?>

<!-- antiResourceLocking="true" -->
<Context path="/podd-apn"
         reloadable="true"
         cachingAllowed="false"
         antiResourceLocking="true"
         >

  <Resource name="jdbc/facs"              
            type="javax.sql.DataSource" username="${database.username}" password="${database.password}"
            driverClassName="org.postgresql.Driver" 
            url="${database.url}"
            maxActive="8" maxIdle="4"
            global="jdbc/facs" 
            />


</Context>

在您的web.xml中,您应该像这样:

<!-- JNDI -->
  <resource-ref>
    <description>FACs Datasource</description>
    <res-ref-name>jdbc/facs</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref> 


方法二:

在Spring上下文中这样设置:

<jee:jndi-lookup id="dbDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />

您可以使用类似下面的命令在Tomcat的server.xml中声明JNDI资源:

<GlobalNamingResources>
  <Resource name="jdbc/DatabaseName" auth="Container" type="javax.sql.DataSource"
              username="dbUsername" password="dbPasswd"
              url="jdbc:postgresql://localhost/dbname"
              driverClassName="org.postgresql.Driver"
              initialSize="5" maxWait="5000"
              maxActive="120" maxIdle="5"
              validationQuery="select 1"
              poolPreparedStatements="true"/>
</GlobalNamingResources/>

并从Tomcat的web context.xml中引用JNDI资源,如下所示:

<ResourceLink name="jdbc/DatabaseName"
   global="jdbc/DatabaseName"
   type="javax.sql.DataSource"/>


我的问题是保留数据库属性的最佳位置在哪里?应该将它们放置在server.xml还是context.xml中

另外,如果我有2个数据库,是否应该使用两个配置?

另外,最佳做法是直接将它们放置在server.xml或context.xml中吗?还是需要通过Tomcat Manager GUI控制台进行配置?

谢谢!

Answers:


27

我更喜欢从 user1016403描述的方法1方法2 中获得最大收益的第三种方法

方法3

  1. 将数据库属性保存在 server.xml
  2. server.xml从Web应用程序引用数据库属性META-INF/context.xml

方法3的好处

尽管出于安全原因第一点很有用,但第二点对于从Web应用程序引用服务器属性值也很有用,即使服务器属性值会发生变化。

此外,将服务器上的资源定义与Web应用程序的使用脱钩可以使这种配置在具有各种复杂性的组织之间可伸缩,其中不同的团队在不同的层/层上工作:如果管理员共享相同的资源,则服务器管理员团队可以在不与开发人员团队冲突的情况下工作每个资源的开发人员的JNDI名称。

方法3的实施

定义JNDI名称jdbc/ApplicationContext_DatabaseName

使用类似这样的声明jdbc/ApplicationContext_DatabaseName在Tomcat的各种属性和值server.xml

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContext_DatabaseName" auth="Container" type="javax.sql.DataSource"
              username="dbUsername" password="dbPasswd"
              url="jdbc:postgresql://localhost/dbname"
              driverClassName="org.postgresql.Driver"
              initialSize="5" maxWait="5000"
              maxActive="120" maxIdle="5"
              validationQuery="select 1"
              poolPreparedStatements="true"/>
</GlobalNamingResources/>

jdbc/ApplicationContext_DatabaseName通过属性META-INF/context.xmljava:comp/env/指定的应用程序专用JNDI上下文从Web应用程序链接的name属性:

<Context path="/ApplicationContext" ... >
  <!--
    "global" attribute links to GlobalNamingResources in the ${catalina.base}/conf/server.xml (server administrator team)
    "name" attribute is relative to the application-private JNDI context java:comp/env/ and is looked up from the java web application (application developer team)
  -->
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName" name="jdbc/DatabaseName" type="javax.sql.DataSource"/>
</Context>

最后,为了使用JNDI资源,请jdbc/DatabaseName在Web应用程序的部署描述符中指定JNDI名称:

<resource-ref>
    <description>DatabaseName's Datasource</description>
    <res-ref-name>jdbc/DatabaseName</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref> 

在Spring上下文中:

<jee:jndi-lookup id="DatabaseNameDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />

方法3的缺点

如果更改了JNDI名称server.xmlMETA-INF/context.xml则必须同时编辑和和,并且必须进行部署。但是,这种情况很少见。

方法3的变化

一个Web应用程序使用的许多数据源

只需将配置添加到Tomcat的server.xml

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContext_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContext_DatabaseName2" ... />
  ...
</GlobalNamingResources/>

META-INF/context.xml通过属性中java:comp/env/指定的应用程序专用JNDI上下文添加链接Web应用程序name

<Context path="/ApplicationContext" ... >
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName1" name="jdbc/DatabaseName1" ... />
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName2" name="jdbc/DatabaseName2" ... />
  ...
</Context>

最后,在Web应用程序的部署描述符中添加JNDI资源使用情况:

<resource-ref>
    <description>DatabaseName1's Datasource</description>
    <res-ref-name>jdbc/DatabaseName1</res-ref-name> ... 
</resource-ref> 
<resource-ref>
    <description>DatabaseName2's Datasource</description>
    <res-ref-name>jdbc/DatabaseName2</res-ref-name> ... 
</resource-ref>
...

在Spring上下文中:

<jee:jndi-lookup id="DatabaseName1DataSource"
   jndi-name="jdbc/DatabaseName1" ... />
<jee:jndi-lookup id="DatabaseName2DataSource"
   jndi-name="jdbc/DatabaseName2" ... />
...


同一台服务器上的许多Web应用程序使用的许多数据源

只需将配置添加到Tomcat的server.xml

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContextX_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContextX_DatabaseName2" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName2" ... />
  ...
</GlobalNamingResources/>

其他配置应该可以从以前的变化情况中得出。


同一服务器上许多Web应用程序使用的同一数据库的许多数据源

在这种情况下,Tomcat的server.xml配置如下:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContextX_DatabaseName" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName" ... />

最终出现在两个不同的Web应用程序中,META-INF/context.xml 例如:

<Context path="/ApplicationContextX" ... >
  <ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>

就像:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>

所以有人可能会担心的是,同样name="jdbc/DatabaseName"是抬起头,然后使用由部署在同一服务器上的两个不同的应用程序:这不是一个问题,因为jdbc/DatabaseName是一个应用程序私有JNDI上下文java:comp/env/,因此ApplicationContextX 使用java:comp/env/不能(根据设计)查找链接到的资源global="jdbc/ApplicationContextY_DatabaseName"

当然,如果您放心而又不用担心,可以使用其他命名策略,例如:

<Context path="/ApplicationContextX" ... >
  <ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/applicationXprivateDatabaseName" ... />
</Context>

就像:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/applicationYprivateDatabaseName" ... />
</Context>

有关“同一服务器上许多Web应用程序使用的同一个数据库的许多数据源”场景的问题...<Resource name="jdbc/ApplicationContextX_DatabaseName" ... /> <Resource name="jdbc/ApplicationContextY_DatabaseName" ... /> 如果资源是连接池,这是否将为您提供两个单独的池,每个Webapp一个?而如果我将两个Web应用程序都链接到一个资源,那么将只有一个连接池,对吗?有什么理由更喜欢一个?(每个Web应用程序有一个单独的数据库连接池,而所有Web应用程序有一个共享的连接池)?谢谢。
Rebeccah 2014年

1
@Rebeccah-问题1:如果资源是连接池,这是否会为您提供两个单独的池,每个Web应用程序一个?A1:是的。
taringamberini 2014年

1
@Rebeccah-问题2:如果我将两个Web应用程序都链接到一个资源,那么将只有一个连接池,对吗?A2:正确。
taringamberini 2014年

2
@Rebeccah-Q3:有什么理由比另一个更喜欢?(每个Web应用程序有一个单独的数据库连接池,而所有Web应用程序有一个共享的连接池)?A3:我更喜欢“每个webapp一个单独的数据库连接池”,因为我不会因为webAppX的连接池用尽而大量使用webAppX会导致webAppY的运行缓慢;此外,数据库监视和日志记录系统无法区分webAppX和webAppY请求,因此难以理解甚至无法解决问题。
taringamberini 2014年

23

YOUR_APP.xml 文件

我更喜欢方法2(放置所有内容(不仅是配置中的某些属性),而且应该将其放置在Tomcat中特定于应用程序的文件中,而不是将它们放置在全局server.xml或全局中。context.xmlcontext.xml.default YOUR_APP.xml

YOUR_APP.xml文件位于$catalinaHome/conf/<engine>/<host>(例如conf/Catalina/localhost/YOUR_APP.xml)。

特定于应用程序的配置YOUR_APP.xml仅适用于特定应用程序。

引导由MuleSoft发布。并参阅Context容器的官方文档“ Tomcat配置参考”页面。

引用该文档:

各个上下文元素可以明确定义:

•…

•在目录中的单个文件中(扩展名为“ .xml”)$CATALINA_BASE/conf/[enginename]/[hostname]/。上下文路径和版本将从文件的基本名称(文件名减去.xml扩展名)派生。

•…


2
感谢您的答复。如果我将所有属性都放在我们的应用程序META-INF / context.xml中?最好的地方吗?
user1016403

5
我认为将某些属性值放在INSIDE(例如,在META-INF / context.xml中)中并不是一个好方法,因为如果属性更改,则必须重新编译并部署该应用程序。-因此,这几乎就像完全不使用属性并将值直接放在spring config.xml中一样
Ralph

那么哪个地方推荐保留它们呢?
user1016403

2
我只是添加,而不是使用context.xml.default为所有应用程序定义这些应用程序,而可以使用特定于应用程序的上下文配置文件,例如在同一文件夹中的yourapp.xml,它允许您将两次相同战争的部署指向不同的数据库。
usethe4ce

1
没有帮助的答案。它只是陈述了一个偏好,没有提供任何理由。
DavidS

10

方法4

我不使用JNDI,而是使用.properties文件并在程序初始化期间而不是在配置时构建复杂的对象

您已经使用过Spring,可以DataSource通过以下方法轻松构造它:

<context:property-placeholder location="classpath:app.properties"/>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@${db.host}:${db.port}:${db.user}"/>
    <property name="username" value="${db.user}"/>
    <property name="password" value="${db.pass}"/>
</bean>

我完全同意拉尔夫使用部署描述符中$CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml,而是JNDI我喜欢简单的键值文件!

使用Spring将上述属性注入到bean字段中很容易:

@Value("${db.user}") String defaultSchema;

而不是JNDI:

@Inject ApplicationContext context;
Enviroment env = context.getEnvironment();
String defaultSchema = env.getProperty("db.user");

还请注意,EL允许这样做(默认值和深度递归替换):

@Value('${db.user:testdb}') private String dbUserName;

<property name='username' value='${db.user.${env}}'/>

为了外部化.properties文件,我使用了具有org.apache.catalina.loader.VirtualWebappLoader的现代Tomcat 7 :

<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
        virtualClasspath="/srv/web/app/"/>

因此,您的devop会填充virtualClasspath每个应用程序独立的本地外部完整路径,并将其放置app.properties在该目录的本地。

也可以看看:


0

您还可以将JNDI URL支持用于不同的应用程序配置,以进行测试,集成测试和生产。

<Context>
...
<Resource auth="Container" factory="com.benasmussen.jndi.url.URLFactory" 
name="url/MyUrl" type="java.net.URL" url="file:///your/path/to/file"/>
...
</Context>

<jee:jndi-lookup id="myUrl" jndi-name="java:comp/env/url/MyUrl" expected-type="java.net.URL" />

签出GitHub项目Tomcat JNDI URL Support,以为Tomcat服务器启用JNDI URL支持。


0

步骤1:context.xml

    <Context path="/projectname">
  <Resource auth="Container" 
            driverClassName="com.mysql.jdbc.Driver"
            logAbandoned="true" 
            maxActive="100" ``
            maxIdle="30" 
            maxWait="10000" 
            name="refname" 
            removeAbandoned="true" 
            removeAbandonedTimeout="60" 
            type="javax.sql.DataSource" 
            url="jdbc:mysql://localhost:8080/dbname" 
            username="root"
            password="root"/>
</Context>

第2步:web.xml

<resource-ref>
        <description>DB Connection</description>
        <res-ref-name>refname</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

步骤3:创建一个类以获取连接

Connection connection = null;        
            Context context = (Context) new InitialContext().lookup("java:comp/env");
            DataSource ds = (DataSource) context.lookup("refname");
            connection = ds.getConnection();

一切都准备好了

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.