由于项目需要,需要在openfire消息服务器中引入druid数据库连接池。刚开始做的时候,一头雾水,只在网络上检索到jndi的改造方式,以及纯java语言引入druid数据库连接池的方式。在和openfire结合的时候,不知道该如何下手。
首先需要了解的是,openfire内部提供了三个实现ConnectionProvider的Provider,分别是JNDIDataSourceProvider、EmbeddedConnectionProvider、DefaultConnectionProvider。这里我并没有采用源码里提供的三个provider,另写了一个自定义的DruidDatasourceProvider。
代码示例如下:
package org.jivesoftware.database;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.slf4j.Logger;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
public class DruidDataSourceProvider implements ConnectionProvider{
private Properties settings;
private String serverURL;
private DruidDataSource dataSource;
private String driver;
private String username;
private String password;
private int minConnections = 3;
private int maxConnections = 10;
private String testSQL = "";
private Boolean testBeforeUse = true;
private Boolean testAfterUse = true;
private double connectionTimeout = 0.5;
@Override
public boolean isPooled() {
return true;
}
@Override
public Connection getConnection() throws SQLException {
try {
Class.forName("com.mysql.jdbc.Driver");
return dataSource.getConnection();
}
catch (ClassNotFoundException e) {
throw new SQLException("DruidConnectionProvider: Unable to find driver: "+e);
}
}
@Override
public void start() {
loadProperties();
dataSource = new DruidDataSource();
//设置连接参数
dataSource.setUrl(settings.getProperty(Config.DRUID_URL));
dataSource.setDriverClassName(settings.getProperty(Config.DRUID_DRIVER));
dataSource.setUsername(settings.getProperty(Config.DRUID_USERNAME));
dataSource.setPassword(settings.getProperty(Config.DRUID_PASSWORD));
//配置初始化大小、最小、最大
dataSource.setInitialSize(1);
dataSource.setMinIdle(1);
dataSource.setMaxActive(20);
//连接泄漏监测
dataSource.setRemoveAbandoned(true);
dataSource.setRemoveAbandonedTimeout(30);
//配置获取连接等待超时的时间
dataSource.setMaxWait(20000);
//配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
dataSource.setTimeBetweenEvictionRunsMillis(20000);
//防止过期
dataSource.setValidationQuery("SELECT 'x'");
dataSource.setTestWhileIdle(true);
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
dataSource.setPoolPreparedStatements(false);
try {
dataSource.setFilters("stat");
dataSource.init();
}catch (Exception e){
System.out.println("wrong!");
}
}
private void loadProperties() {
settings = new Properties();
settings.setProperty(Config.DRUID_URL, JiveGlobals.getXMLProperty(Config.DRUID_URL));
settings.setProperty(Config.DRUID_DRIVER, JiveGlobals.getXMLProperty(Config.DRUID_DRIVER));
settings.setProperty(Config.DRUID_USERNAME, JiveGlobals.getXMLProperty(Config.DRUID_USERNAME));
settings.setProperty(Config.DRUID_PASSWORD, JiveGlobals.getXMLProperty(Config.DRUID_PASSWORD));
}
@Override
public void restart() {
// Kill off pool.
destroy();
// Start a new pool.
start();
}
@Override
public void destroy() {
dataSource.close();
}
/**
* Returns the JDBC driver classname used to make database connections.
* For example: com.mysql.jdbc.Driver
*
* @return the JDBC driver classname.
*/
public String getDriver() {
return driver;
}
/**
* Sets the JDBC driver classname used to make database connections.
* For example: com.mysql.jdbc.Driver
*
* @param driver the fully qualified JDBC driver name.
*/
public void setDriver(String driver) {
this.driver = driver;
saveProperties();
}
/**
* Returns the JDBC connection URL used to make database connections.
*
* @return the JDBC connection URL.
*/
public String getServerURL() {
return serverURL;
}
/**
* Sets the JDBC connection URL used to make database connections.
*
* @param serverURL the JDBC connection URL.
*/
public void setServerURL(String serverURL) {
this.serverURL = serverURL;
saveProperties();
}
/**
* Returns the username used to connect to the database. In some cases,
* a username is not needed so this method will return null.
*
* @return the username used to connect to the datbase.
*/
public String getUsername() {
return username;
}
/**
* Sets the username used to connect to the database. In some cases, a
* username is not needed so null should be passed in.
*
* @param username the username used to connect to the database.
*/
public void setUsername(String username) {
this.username = username;
saveProperties();
}
/**
* Returns the password used to connect to the database. In some cases,
* a password is not needed so this method will return null.
*
* @return the password used to connect to the database.
*/
public String getPassword() {
return password;
}
/**
* Sets the password used to connect to the database. In some cases, a
* password is not needed so null should be passed in.
*
* @param password the password used to connect to the database.
*/
public void setPassword(String password) {
this.password = password;
saveProperties();
}
/**
* Returns the minimum number of connections that the pool will use. This
* should probably be at least three.
*
* @return the minimum number of connections in the pool.
*/
public int getMinConnections() {
return minConnections;
}
/**
* Sets the minimum number of connections that the pool will use. This
* should probably be at least three.
*
* @param minConnections the minimum number of connections in the pool.
*/
public void setMinConnections(int minConnections) {
this.minConnections = minConnections;
saveProperties();
}
/**
* Returns the maximum number of connections that the pool will use. The
* actual number of connections in the pool will vary between this value
* and the minimum based on the current load.
*
* @return the max possible number of connections in the pool.
*/
public int getMaxConnections() {
return maxConnections;
}
/**
* Sets the maximum number of connections that the pool will use. The
* actual number of connections in the pool will vary between this value
* and the minimum based on the current load.
*
* @param maxConnections the max possible number of connections in the pool.
*/
public void setMaxConnections(int maxConnections) {
this.maxConnections = maxConnections;
saveProperties();
}
/**
* Returns the amount of time between connection recycles in days. For
* example, a value of .5 would correspond to recycling the connections
* in the pool once every half day.
*
* @return the amount of time in days between connection recycles.
*/
public double getConnectionTimeout() {
return connectionTimeout;
}
/**
* Sets the amount of time between connection recycles in days. For
* example, a value of .5 would correspond to recycling the connections
* in the pool once every half day.
*
* @param connectionTimeout the amount of time in days between connection
* recycles.
*/
public void setConnectionTimeout(double connectionTimeout) {
this.connectionTimeout = connectionTimeout;
saveProperties();
}
/**
* Returns the SQL statement used to test if a connection is valid.
*
* @return the SQL statement that will be run to test a connection.
*/
public String getTestSQL() {
return testSQL;
}
/**
* Sets the SQL statement used to test if a connection is valid. House keeping
* and before/after connection tests make use of this. This
* should be something that causes the minimal amount of work by the database
* server and is as quick as possible.
*
* @param testSQL the SQL statement that will be run to test a connection.
*/
public void setTestSQL(String testSQL) {
this.testSQL = testSQL;
}
/**
* Returns whether returned connections will be tested before being handed over
* to be used.
*
* @return True if connections are tested before use.
*/
public Boolean getTestBeforeUse() {
return testBeforeUse;
}
/**
* Sets whether connections will be tested before being handed over to be used.
*
* @param testBeforeUse True or false if connections are to be tested before use.
*/
public void setTestBeforeUse(Boolean testBeforeUse) {
this.testBeforeUse = testBeforeUse;
}
/**
* Returns whether returned connections will be tested after being returned to
* the pool.
*
* @return True if connections are tested after use.
*/
public Boolean getTestAfterUse() {
return testAfterUse;
}
/**
* Sets whether connections will be tested after being returned to the pool.
*
* @param testAfterUse True or false if connections are to be tested after use.
*/
public void setTestAfterUse(Boolean testAfterUse) {
this.testAfterUse = testAfterUse;
}
/**
* Save properties as Jive properties.
*/
private void saveProperties() {
JiveGlobals.setXMLProperty("database.druidProvider.driver", driver);
JiveGlobals.setXMLProperty("database.druidProvider.serverURL", serverURL);
JiveGlobals.setXMLProperty("database.druidProvider.username", username);
JiveGlobals.setXMLProperty("database.druidProvider.password", password);
JiveGlobals.setXMLProperty("database.druidProvider.testSQL", testSQL);
JiveGlobals.setXMLProperty("database.druidProvider.testBeforeUse", testBeforeUse.toString());
JiveGlobals.setXMLProperty("database.druidProvider.testAfterUse", testAfterUse.toString());
JiveGlobals.setXMLProperty("database.druidProvider.minConnections",
Integer.toString(minConnections));
JiveGlobals.setXMLProperty("database.druidProvider.maxConnections",
Integer.toString(maxConnections));
JiveGlobals.setXMLProperty("database.druidProvider.connectionTimeout",
Double.toString(connectionTimeout));
}
}
然后需要在*/src/web/setup下对该provider进行配置,这里可以参考DefaultConnectionProvider的配置方式。
没有什么问题之后,对openfire源码进行编译,生成的openfire.jar替换原先服务器中lib目录下的openfire.jar依赖包。
然后在openfire的配置文件openfire.xml中对druid数据库连接池进行配置。参考如下:
<connectionProvider>
<className>org.jivesoftware.database.DruidDataSourceProvider</className>
</connectionProvider>
<database>
<druidProvider>
<driver>com.mysql.jdbc.Driver</driver>
<serverURL>jdbc:mysql://localhost:port/openfire?useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8</serverURL>
<username>*****</username>
<password>*****</password>
<testSQL>select 1</testSQL>
<testBeforeUse>false</testBeforeUse>
<testAfterUse>false</testAfterUse>
<minConnections>5</minConnections>
<maxConnections>200</maxConnections>
<connectionTimeout>1.0</connectionTimeout>
</druidProvider>
</database>
另外还需要在openfire的依赖库中添加druid依赖包。
下载地址:http://central.maven.org/maven2/com/alibaba/druid/
到这里引入druid数据库链接池已经基本完成。
下面提供监控页面的修改地址。
在openfire/plugins/admin/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>true</param-value>
</init-param>
<init-param>
<!-- 用户名 -->
<param-name>loginUsername</param-name>
<param-value>******</param-value>
</init-param>
<init-param>
<!-- 密码 -->
<param-name>loginPassword</param-name>
<param-value>******</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>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DruidWebStatFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这里配置基本完毕,重启openfire服务器。
http://localhost:9090/druid/index.html中就可以看到监控平台了。