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

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

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

方法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>


方法2:

在 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"/>


我的问题是,保存数据库属性的最佳位置在哪里? 它们应该放在 Xml还是 Xml中?

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

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

谢谢!

92463 次浏览

YOUR_APP.xml文件

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

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

应用程序特定的 YOUR_APP.xml中的配置仅对特定的应用程序可用。

请参阅 MuleSoft 出版的 向导。请参阅 上下文容器的官方文档 Tomcat 配置参考

引用那份文件:

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

•。

‧在个别档案内。Xml”扩展名)。上下文路径和版本将从文件的基名(文件名减去。Xml 扩展名)。

•。

您还可以为测试、集成测试和生产的不同应用程序配置使用 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 的支持,以启用对 Tomcat 服务器的 JNDI URL 支持。

我更喜欢采用第三种方法,从中获得最佳效果 方法1 进场二 由 user1016403描述

进场3

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

方法3的好处

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

此外,将服务器上的资源定义与 Web 应用程序使用的资源定义分离,使得这种配置可以在不同复杂性的组织之间进行扩展,在这些组织中,不同的团队在不同的层/层上工作: 如果管理员为每个资源与开发人员共享相同的 JNDI 名称,服务器管理员团队可以在不与开发人员团队发。

方法3的实施

定义 JNDI 名称 jdbc/ApplicationContext_DatabaseName

在 Tomcat 的 server.xml中声明 jdbc/ApplicationContext_DatabaseName的各种属性和值,方法如下:

<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/>

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

<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 资源,在 web 应用程序的部署描述符中指定 JNDI 名称 jdbc/DatabaseName:

<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/>

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

<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" ... />

最终会出现在两个不同的网络应用程序 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>

进场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中使用部署描述符,但是我更喜欢普通的键-值文件!

使用 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文件,我使用现代的 Tomcat 7,它有 加载程序,虚拟网络应用加载程序:

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

因此,Devops 使用本地外部完整路径填充 virtualClasspath,这对于每个应用程序是独立的,并将本地 app.properties放到该目录中。

参见:

步骤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();

一切都准备好了