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

use*_*403 78 java spring jndi datasource

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

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

方法1:

在Spring配置中,您可能会遇到以下情况:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/facs"/>
Run Code Online (Sandbox Code Playgroud)

然后在你的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>
Run Code Online (Sandbox Code Playgroud)

在你的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> 
Run Code Online (Sandbox Code Playgroud)


方法2:

在Spring上下文中设置如下:

<jee:jndi-lookup id="dbDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />
Run Code Online (Sandbox Code Playgroud)

您可以使用以下内容在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/>
Run Code Online (Sandbox Code Playgroud)

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

<ResourceLink name="jdbc/DatabaseName"
   global="jdbc/DatabaseName"
   type="javax.sql.DataSource"/>
Run Code Online (Sandbox Code Playgroud)


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

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

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

谢谢!

tar*_*ini 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_DatabaseNameserver.xml东西在Tomcat中声明各种属性和值:

<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/>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

最后,为了使用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> 
Run Code Online (Sandbox Code Playgroud)

并在Spring上下文中:

<jee:jndi-lookup id="DatabaseNameDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />
Run Code Online (Sandbox Code Playgroud)

方法3的缺点

如果JNDI名称得到改变那么无论是server.xmlMETA-INF/context.xml将要进行编辑和部署是必要的; 尽管如此,这种情况很少见.

接近3种变化

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

只需向Tomcat添加配置server.xml:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContext_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContext_DatabaseName2" ... />
  ...
</GlobalNamingResources/>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

最后在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>
...
Run Code Online (Sandbox Code Playgroud)

并在Spring上下文中:

<jee:jndi-lookup id="DatabaseName1DataSource"
   jndi-name="jdbc/DatabaseName1" ... />
<jee:jndi-lookup id="DatabaseName2DataSource"
   jndi-name="jdbc/DatabaseName2" ... />
...
Run Code Online (Sandbox Code Playgroud)


许多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/>
Run Code Online (Sandbox Code Playgroud)

其他配置应该可以从以前的变异案例中推断出来.


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

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

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContextX_DatabaseName" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName" ... />
Run Code Online (Sandbox Code Playgroud)

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

<Context path="/ApplicationContextX" ... >
  <ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>
Run Code Online (Sandbox Code Playgroud)

并喜欢:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>
Run Code Online (Sandbox Code Playgroud)

所以有人可能会担心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>
Run Code Online (Sandbox Code Playgroud)

并喜欢:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/applicationYprivateDatabaseName" ... />
</Context>
Run Code Online (Sandbox Code Playgroud)

  • @Rebeccah - Q1:如果资源是连接池,这会给你两个单独的池,每个 web 应用程序一个吗?A1:是的,会的。 (2认同)
  • @Rebeccah - Q3:任何理由更喜欢一个到另一个?(每个webapp一个DB连接池与所有webapps共享的一个连接池)?A3:我更喜欢"每个webapp一个独立的数据库连接池",因为由于webAppX的连接池耗尽,我不会因webAppX的密集使用而导致webAppY的速度变慢; 此外,数据库监控和日志记录系统无法区分webAppX和webAppY请求,因此理解和隔离问题将变得困难或更不可能. (2认同)

Ral*_*lph 23

我更喜欢方法2(放置所有东西(不仅是配置中的一些属性),

但是不应将它们放在全局YOUR_APP.xml或全局中server.xml,而应将它放在tomcat中特定的应用程序中.context.xml context.xml.default

YOUR_APP.xml文件位于YOUR_APP.xml(例如conf/Catalina/localhost/YOUR_APP.xml).

特定于应用程序的配置$catalinaHome/conf/<engine>/<host>仅适用于特定应用程序.

  • 我不认为放置一些属性值INSIDE(例如META-INF/context.xml中的示例)应用程序是一种很好的方法,因为如果属性发生更改,则必须重新编译和部署应用程序. - 所以这几乎就像不使用任何属性并将值直接放在spring config.xml中一样 (5认同)
  • 谢谢你的回答.如果我将所有属性放在我们的应用程序META-INF/context.xml中?这是最好的地方吗? (2认同)
  • 我只是添加,而不是使用context.xml.default为所有应用程序定义它们,而可以使用特定于应用程序的上下文配置文件,例如在同一文件夹中的yourapp.xml,这使您可以将两次相同战争的部署指向不同的数据库。 (2认同)

gav*_*koa 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>
Run Code Online (Sandbox Code Playgroud)

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

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

@Value("${db.user}") String defaultSchema;
Run Code Online (Sandbox Code Playgroud)

而不是JNDI:

@Inject ApplicationContext context;
Enviroment env = context.getEnvironment();
String defaultSchema = env.getProperty("db.user");
Run Code Online (Sandbox Code Playgroud)

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

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

<property name='username' value='${db.user.${env}}'/>
Run Code Online (Sandbox Code Playgroud)

要外化.properties文件,我使用带有org.apache.catalina.loader.VirtualWebappLoader的现代Tomcat 7 :

<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
        virtualClasspath="/srv/web/app/"/>
Run Code Online (Sandbox Code Playgroud)

所以你的devops填充virtualClasspath了本地外部完整路径,每个应用程序是独立的,并且放置app.properties在该dir的本地.

也可以看看: