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

来源:互联网 发布:深圳软件开发工资水平 编辑:程序博客网 时间:2024/05/22 06:23

如何在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

原创粉丝点击