演示如何在predix上使用postgres服务
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
首先需要确保在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配置。
在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>
在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