如何在predix上构建使用postgresql服务的Java Webapp

如何在predix上构建使用postgresql服务的Java Webapp

目的

演示如何在predix上使用postgres服务

webapp 特性

  • 在本地使用h2数据库作为数据源
  • 在predix云端使用postgres服务作为数据源
  • 云端部署的时候禁止spring auto-reconfiguration, 隐藏我们可以使用自定义的数据库连接池
  • 使用druid jdbc连接池来monitor数据库使用
  • 在本地时使用h2的web console来查询和处理数据

项目源文件

https://github.com/iintothewind/PsqlSimple

一些需要注意的地方

数据库初始化脚本

我们可以在src/main/resources/h2/下面创建初始化数据库的sql文件,等webapp启动的时候可以通过spring的脚本初始化帮我们初始化数据库。
spring配置里面通过调用初始化数据库的配置在src/main/resources/spring/mvc.xml文件中:

 <jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
    <jdbc:script location="classpath:h2/init.sql"/>
 </jdbc:initialize-database>

另外不要忘了在xml头部引入jdbc的xmlns和xsi:schemaLocation

H2数据库的web console配置

首先需要确保在pom文件中引入h2, 需要确保h2的scope为runtime:

    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>1.4.192</version>
      <scope>runtime</scope>
    </dependency>

然后在src/main/webapp/WEB-INF/web.xml中加入:

  <servlet>
    <servlet-name>H2Console</servlet-name>
    <servlet-class>org.h2.server.web.WebServlet</servlet-class>
    <init-param>
      <param-name>webAllowOthers</param-name>
      <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>H2Console</servlet-name>
    <url-pattern>/h2/*</url-pattern>
  </servlet-mapping>

数据库连接

predix的jdbc连接配置如果引入的spring就会很容易出问题,因为默认的Java Buildpack会检测spring的jdbc datasource配置,然后自动替换掉, 这样的话我们的一些连接池优化就没办法做了,如果需要我们自己配置jdbc连接就必须要禁掉Java Buildpack的auto-reconfiguration, 如下在manifest.xml中
application子项下面加入JBP_CONFIG_SPRING_AUTO_RECONFIGURATION: '{enabled: false}'

applications:
- name: psqlsimple   env:
    JBP_CONFIG_SPRING_AUTO_RECONFIGURATION: '{enabled: false}'

这样的话Java Buildpack就不会自动替换我们的jdbc连接配置了。

接下来我们需要写一个类来帮我获取jdbc连接所需要的参数, 因为如果我们在创建app的时候绑定了jdbc服务,那么host,port,database, username,password, jdbc_uri等参数等参数将会出现在这个app的system env中,
我们通过调用System.getenv("VCAP_SERVICES")就可以获取到这些参数,predix.psql.config.CloudCfg是用来自动获取本地jdbc配置或者云端system env中postgres参数的类,源代码如下:

package predix.psql.config;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValueFactory;
import javaslang.control.Try;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CloudCfg {
  private final static Logger log = LoggerFactory.getLogger(CloudCfg.class);
  private final String jdbcHost;
  private final int jdbcPort;
  private final String jdbcDatabase;
  private final String jdbcUserName;
  private final String jdbcPassword;
  private final String jdbcUrl;

  public CloudCfg() {
    Config cfg = Try.of(() -> (Config) ConfigFactory.parseString(System.getenv("VCAP_SERVICES")).getConfigList("postgres").get(0))
      .getOrElse(ConfigFactory.parseResources(this.getClass().getClassLoader(), "database.properties").withFallback(ConfigFactory.empty()
        .withValue("credentials.host", ConfigValueFactory.fromAnyRef("localhost"))
        .withValue("credentials.port", ConfigValueFactory.fromAnyRef(5432))
        .withValue("credentials.database", ConfigValueFactory.fromAnyRef("test"))
        .withValue("credentials.username", ConfigValueFactory.fromAnyRef("postgres"))
        .withValue("credentials.password", ConfigValueFactory.fromAnyRef("root"))
        .withValue("credentials.jdbc_uri", ConfigValueFactory.fromAnyRef("jdbc:h2:mem:test;MVCC=TRUE;DB_CLOSE_DELAY=-1;MODE=POSTGRESQL"))));
    jdbcHost = cfg.getString("credentials.host");
    jdbcPort = cfg.getInt("credentials.port");
    jdbcDatabase = cfg.getString("credentials.database");
    jdbcUserName = cfg.getString("credentials.username");
    jdbcPassword = cfg.getString("credentials.password");
    jdbcUrl = cfg.getString("credentials.jdbc_uri");
  }

  public String getJdbcHost() {
    return jdbcHost;
  }

  public int getJdbcPort() {
    return jdbcPort;
  }

  public String getJdbcDatabase() {
    return jdbcDatabase;
  }

  public String getJdbcUserName() {
    return jdbcUserName;
  }

  public String getJdbcPassword() {
    return jdbcPassword;
  }

  public String getJdbcUrl() {
    return jdbcUrl;
  }
}

CloudCfg这个类将会首先尝试读取system env的VCAP_SERVICES变量,并解析postgres参数配置, 如果获取失败,则尝试读取系统根目录的database.properties 文件获取配置,如果再次失败,则尝试使用代码中给定
的fallback配置。

druid数据库连接池的配置和监控设置

首先在spring中使用druid 数据库连接池作为数据源

在src/main/resources/spring/mvc.xml中加入

  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="url" value="#{cloudCfg.jdbcUrl}"/>
    <property name="username" value="#{cloudCfg.jdbcUserName}"/>
    <property name="password" value="#{cloudCfg.jdbcPassword}"/>
    <property name="initialSize" value="1"/>
    <property name="minIdle" value="1"/>
    <property name="maxActive" value="50"/>
    <!--<property name="maxWait" value="60000"/>-->
    <property name="timeBetweenEvictionRunsMillis" value="60000"/>
    <property name="minEvictableIdleTimeMillis" value="300000"/>
    <property name="validationQuery" value="SELECT 'x'"/>
    <property name="testWhileIdle" value="true"/>
    <property name="testOnBorrow" value="false"/>
    <property name="testOnReturn" value="false"/>
    <property name="removeAbandoned" value="true"/>
    <property name="removeAbandonedTimeout" value="10"/>
    <property name="logAbandoned" value="true"/>
    <property name="poolPreparedStatements" value="true"/>
    <property name="maxPoolPreparedStatementPerConnectionSize" value="5000"/>
    <property name="proxyFilters">
      <list>
        <ref bean="statFilter"/>
        <ref bean="wallFilter"/>
        <ref bean="slf4jLogFilter"/>
      </list>
    </property>
  </bean>

  <bean id="cloudCfg" class="predix.psql.config.CloudCfg"/>

  <bean id="statFilter" class="com.alibaba.druid.filter.stat.StatFilter">
    <property name="logSlowSql" value="true"/>
    <property name="slowSqlMillis" value="5000"/>
    <property name="mergeSql" value="true"/>
  </bean>

  <bean id="wallFilter" class="com.alibaba.druid.wall.WallFilter">
    <property name="dbType" value="postgresql"/>
    <property name="logViolation" value="true"/>
    <property name="throwException" value="false"/>
  </bean>

  <bean id="slf4jLogFilter" class="com.alibaba.druid.filter.logging.Slf4jLogFilter">
    <property name="statementExecutableSqlLogEnable" value="true"/>
    <property name="connectionLogErrorEnabled" value="true"/>
    <property name="statementLogErrorEnabled" value="true"/>
    <property name="resultSetLogErrorEnabled" value="true"/>
  </bean>
  • DruidDataSource的url,username,password属性需要从cloudCfg这个bean中获取。
  • statFilter用来支持web端的页面监控
  • wallFilter提供sql入侵检测支持
  • slf4jLogFilter提供sql执行日志支持

在src/main/webapp/WEB-INF/web.xml中加入:

  <servlet>
    <servlet-name>DruidStatView</servlet-name>
    <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
    <init-param>
      <param-name>resetEnable</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>loginUsername</param-name>
      <param-value>druid</param-value>
    </init-param>
    <init-param>
      <param-name>loginPassword</param-name>
      <param-value>druid</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>DruidStatView</servlet-name>
    <url-pattern>/druid/*</url-pattern>
  </servlet-mapping>
  <filter>
    <filter-name>druidWebStatFilter</filter-name>
    <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
    <init-param>
      <param-name>exclusions</param-name>
      <param-value>
        *resource/*,*resources/*,/druid*,/public/*,*.js.xhtml,*.css.xhtml,*.png.xhtml,*.jpg.xhtml,*.svg.xhtml,*.swf
      </param-value>
    </init-param>
    <init-param>
      <param-name>principalSessionName</param-name>
      <param-value>sessionInfo</param-value>
    </init-param>
    <init-param>
      <param-name>profileEnable</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>druidWebStatFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

运行

请参考https://github.com/iintothewind/PsqlSimple 的readme来部署和运行app

你可能感兴趣的:(java,postgres,Predix,buidpack)