首页 文章

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

提问于
浏览
75

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

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

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

Approach 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 回答

  • 26

    我更喜欢从 Approach 1Approach 2 described by user1016403获得最佳效果的第三种方法 .

    方法3

    • server.xml 上保存数据库属性

    • 从Web应用程序 META-INF/context.xml 引用 server.xml 数据库属性

    方法3的好处

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

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

    方法3实施

    定义JNDI名称 jdbc/ApplicationContext_DatabaseName .

    使用以下内容声明 jdbc/ApplicationContext_DatabaseName 's various properties and values in Tomcat' s 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/>
    

    通过 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种变化

    Many data sources used by one web application

    只需将配置添加到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" ... />
    ...
    

    Many data sources used by many web application on the same server

    只需将配置添加到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/>
    

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

    Many data sources to the same database used by many web application on the same server

    在这种情况下,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>
    

    所以有人可能会担心同一个服务器上部署的两个不同应用程序查找并使用相同的事实:这不是问题,因为 jdbc/DatabaseName 是应用程序私有JNDI上下文 java:comp/env/ ,所以 ApplicationContextX by using 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>
    
  • 0

    我更喜欢方法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 中的配置仅适用于特定应用程序 .

  • 9

    Approach 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 放到该目录 .

    也可以看看:

  • 22

    您还可以将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();
    

    一切都准备好了

相关问题