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

时间:2013-02-25 09:55:45

标签: java spring datasource jndi

我正在尝试使用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> 


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


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

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

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

谢谢!

5 个答案:

答案 0 :(得分:26)

我更喜欢采用第三种方法 方法1 方法2 described by user1016403

方法3

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

    方法3的好处

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

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

    方法3实施

    定义JNDI名称jdbc/ApplicationContext_DatabaseName

    使用以下内容在Tomcat的jdbc/ApplicationContext_DatabaseName中声明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属性中指定的应用程序专用JNDI上下文META-INF/context.xml链接来自Web应用程序java:comp/env/的{​​{1}}属性:

    name

    最后,为了使用JNDI资源,请在Web应用程序的部署描述符中指定JNDI名称<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>

    jdbc/DatabaseName

    并在Spring上下文中:

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

    接近3个缺点

    如果更改了JNDI名称,则必须编辑<jee:jndi-lookup id="DatabaseNameDataSource" jndi-name="jdbc/DatabaseName" expected-type="javax.sql.DataSource" /> server.xml,并且必须进行部署;尽管如此,这种情况很少见。

    接近3种变化

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

    只需将配置添加到Tomcat的META-INF/context.xml

    server.xml

    通过<GlobalNamingResources> <Resource name="jdbc/ApplicationContext_DatabaseName1" ... /> <Resource name="jdbc/ApplicationContext_DatabaseName2" ... /> ... </GlobalNamingResources/> 属性中指定的应用程序专用JNDI上下文META-INF/context.xml添加链接Web应用程序java:comp/env/

    name

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

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

    并在Spring上下文中:

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


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

    只需将配置添加到Tomcat的<jee:jndi-lookup id="DatabaseName1DataSource" jndi-name="jdbc/DatabaseName1" ... /> <jee:jndi-lookup id="DatabaseName2DataSource" jndi-name="jdbc/DatabaseName2" ... /> ...

    server.xml

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


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

    在这种情况下,Tomcat的<GlobalNamingResources> <Resource name="jdbc/ApplicationContextX_DatabaseName1" ... /> <Resource name="jdbc/ApplicationContextX_DatabaseName2" ... /> <Resource name="jdbc/ApplicationContextY_DatabaseName1" ... /> <Resource name="jdbc/ApplicationContextY_DatabaseName2" ... /> ... </GlobalNamingResources/> 配置如:

    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"是应用程序私有JNDI上下文jdbc/DatabaseName,因此使用java:comp/env/ApplicationContextX 无法(按设计)查找链接到java:comp/env/的资源

    当然,如果您在没有这种担心的情况下感到更放松,您可以使用不同的命名策略,例如:

    global="jdbc/ApplicationContextY_DatabaseName"

    并且喜欢:

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

答案 1 :(得分:22)

我更喜欢方法2(放置所有内容(不仅是配置中的某些属性),

但是您应该将它放在全局server.xml或全局context.xml中,而不是将其置于特定于应用程序的 context.xml.default YOUR_APP.xml中Tomcat中。

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

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

答案 2 :(得分:9)

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

我完全同意 Ralph $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/"/>

所以你的devops用virtualClasspath填充本地外部完整路径,每个应用程序是独立的,并将本地app.properties放到该目录。

另见:

答案 3 :(得分: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支持。

答案 4 :(得分: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();

一切都已设定