mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
补充测试,重构代码
This commit is contained in:
@@ -13,6 +13,11 @@ import java.sql.Driver;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* FilterChain to create new connection with placeholder in URL
|
||||
*
|
||||
* @author DigitalSonic
|
||||
*/
|
||||
public class ConnectionConnectFilterChainImpl extends FilterChainImpl {
|
||||
private final static Log LOG = LogFactory.getLog(ConnectionConnectFilterChainImpl.class);
|
||||
|
||||
|
||||
@@ -14,6 +14,11 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* A singleton object to hold Host & Port information.
|
||||
*
|
||||
* @author DigitalSonic
|
||||
*/
|
||||
public class HostAndPortHolder {
|
||||
private static final Log LOG = LogFactory.getLog(ConnectionConnectFilterChainImpl.class);
|
||||
|
||||
@@ -30,18 +35,22 @@ public class HostAndPortHolder {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void loadFromProperties(String file) {
|
||||
public static void loadProperties(String file) {
|
||||
Properties properties = new Properties();
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
InputStream is;
|
||||
InputStream is = null;
|
||||
try {
|
||||
LOG.debug("Trying to load " + file + " from FileSystem.");
|
||||
is = new FileInputStream(file);
|
||||
} catch(FileNotFoundException e) {
|
||||
LOG.debug("Trying to load " + file + " from Classpath.");
|
||||
is = HostAndPortHolder.class.getResourceAsStream(file);
|
||||
try {
|
||||
is = HostAndPortHolder.class.getResourceAsStream(file);
|
||||
} catch (Exception ex) {
|
||||
LOG.warn("Can not load resource " + file, ex);
|
||||
}
|
||||
}
|
||||
if (is != null) {
|
||||
try {
|
||||
|
||||
@@ -10,6 +10,12 @@ import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A thread to run the validation on each host:port.
|
||||
* If some host:port is failed in the validation, we can set test flags in DruidDataSource.
|
||||
*
|
||||
* @author DigitalSonic
|
||||
*/
|
||||
public class HostAndPortValidatorThread implements Runnable {
|
||||
private final static Log LOG = LogFactory.getLog(HostAndPortValidatorThread.class);
|
||||
private DruidDataSource dataSource;
|
||||
@@ -38,8 +44,6 @@ public class HostAndPortValidatorThread implements Runnable {
|
||||
}
|
||||
|
||||
protected void check() {
|
||||
Driver driver = dataSource.getRawDriver();
|
||||
Properties info = dataSource.getConnectProperties();
|
||||
String url = dataSource.getRawJdbcUrl();
|
||||
if (url == null || (url != null &&
|
||||
(url.indexOf("${") == -1 || url.indexOf("}") == -1))) {
|
||||
@@ -49,31 +53,40 @@ public class HostAndPortValidatorThread implements Runnable {
|
||||
String placeHolder = url.substring(url.indexOf("${") + 2, url.indexOf("}"));
|
||||
List<String> values = HostAndPortHolder.getInstance().getAll(placeHolder);
|
||||
for (String v : values) {
|
||||
Connection conn = null;
|
||||
try {
|
||||
String realUrl = url.replace("${" + placeHolder + "}", v);
|
||||
conn = driver.connect(realUrl, info);
|
||||
dataSource.validateConnection(conn);
|
||||
HostAndPortHolder.getInstance().removeBlacklist(v);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Validation FAILED for " + v, e);
|
||||
HostAndPortHolder.getInstance().addBlacklist(v);
|
||||
modifyFlagsIfNeeded();
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
LOG.error("Can not close connection for HostAndPort Validation.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
validateConnection(dataSource, placeHolder, v);
|
||||
}
|
||||
if (HostAndPortHolder.getInstance().getBlacklistSize() == 0) {
|
||||
resetFlagsIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateConnection(DruidDataSource dataSource, String placeHolder, String target) {
|
||||
Driver driver = dataSource.getRawDriver();
|
||||
Properties info = dataSource.getConnectProperties();
|
||||
String url = dataSource.getRawJdbcUrl();
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
LOG.debug("Validating " + target + " every " + sleepSeconds + " seconds.");
|
||||
String realUrl = url.replace("${" + placeHolder + "}", target);
|
||||
conn = driver.connect(realUrl, info);
|
||||
dataSource.validateConnection(conn);
|
||||
HostAndPortHolder.getInstance().removeBlacklist(target);
|
||||
} catch (SQLException e) {
|
||||
LOG.warn("Validation FAILED for " + target, e);
|
||||
HostAndPortHolder.getInstance().addBlacklist(target);
|
||||
modifyFlagsIfNeeded();
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
LOG.error("Can not close connection for HostAndPort Validation.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetFlagsIfNeeded() {
|
||||
if (modifyTestFlags) {
|
||||
dataSource.setTestOnBorrow(oldTestOnBorrow);
|
||||
@@ -85,7 +98,7 @@ public class HostAndPortValidatorThread implements Runnable {
|
||||
if (!modifyTestFlags) {
|
||||
return;
|
||||
}
|
||||
if (oldTestOnReturn || oldTestOnBorrow) {
|
||||
if (!oldTestOnReturn || !oldTestOnBorrow) {
|
||||
dataSource.setTestOnBorrow(true);
|
||||
dataSource.setTestOnReturn(true);
|
||||
}
|
||||
|
||||
@@ -11,22 +11,35 @@ import com.alibaba.druid.support.logging.LogFactory;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* The filter to replace the placeholder in JDBC URL.
|
||||
*
|
||||
* @author DigitalSonic
|
||||
*/
|
||||
public class JdbcUrlHostAndPortReplaceFilter extends FilterAdapter {
|
||||
private final static Log LOG = LogFactory.getLog(HostAndPortValidatorThread.class);
|
||||
|
||||
public static final String DEFAULT_FILE = "/druid-datasource.properties";
|
||||
public static final String DEFAULT_FILE = "datasource.properties";
|
||||
|
||||
private String file = DEFAULT_FILE;
|
||||
|
||||
private int healthCheckIntervalSeconds = 0;
|
||||
private HostAndPortValidatorThread validatorThread;
|
||||
private Thread runningValidatorThread;
|
||||
private boolean isValidatorThreadStarted = false;
|
||||
private boolean modifyTestFlags = false;
|
||||
|
||||
public void init() {
|
||||
if (file == null || file.trim().length() == 0) {
|
||||
file = DEFAULT_FILE;
|
||||
}
|
||||
HostAndPortHolder.loadFromProperties(file);
|
||||
HostAndPortHolder.loadProperties(file);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (runningValidatorThread != null) {
|
||||
runningValidatorThread.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,9 +57,11 @@ public class JdbcUrlHostAndPortReplaceFilter extends FilterAdapter {
|
||||
if (validatorThread == null) {
|
||||
validatorThread = new HostAndPortValidatorThread();
|
||||
validatorThread.setSleepSeconds(healthCheckIntervalSeconds);
|
||||
validatorThread.setModifyTestFlags(modifyTestFlags);
|
||||
}
|
||||
validatorThread.setDataSource((DruidDataSource) dataSource);
|
||||
new Thread(validatorThread).start();
|
||||
runningValidatorThread = new Thread(validatorThread);
|
||||
runningValidatorThread.start();
|
||||
isValidatorThreadStarted = true;
|
||||
} else {
|
||||
LOG.warn("The DataSource is not a DruidDataSource, ignore HostAndPortValidator.");
|
||||
@@ -64,4 +79,8 @@ public class JdbcUrlHostAndPortReplaceFilter extends FilterAdapter {
|
||||
public void setValidatorThread(HostAndPortValidatorThread validatorThread) {
|
||||
this.validatorThread = validatorThread;
|
||||
}
|
||||
|
||||
public void setModifyTestFlags(boolean modifyTestFlags) {
|
||||
this.modifyTestFlags = modifyTestFlags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,20 @@ import org.junit.Test;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Test class for HostAndPortHolder
|
||||
*
|
||||
* @author DigitalSonic
|
||||
*/
|
||||
public class HostAndPortHolderTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
HostAndPortHolder.loadFromProperties("/com/alibaba/druid/filter/url/datasource.properties");
|
||||
HostAndPortHolder.loadProperties("/com/alibaba/druid/filter/url/datasource.properties");
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -20,6 +28,13 @@ public class HostAndPortHolderTest {
|
||||
HostAndPortHolder.getInstance().clearBlacklist();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadFromFileNotExisted() {
|
||||
int size = HostAndPortHolder.getInstance().getHolder().size();
|
||||
HostAndPortHolder.loadProperties("FILE_NOT_FOUND");
|
||||
assertEquals(size, HostAndPortHolder.getInstance().getHolder().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadFromProperties() {
|
||||
Map<String, List<String>> holder = HostAndPortHolder.getInstance().getHolder();
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.alibaba.druid.filter.url;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Test class for HostAndPortValidatorThread
|
||||
*
|
||||
* @author DigitalSonic
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:com/alibaba/druid/filter/url/dataSource.xml")
|
||||
public class HostAndPortValidatorThreadTest {
|
||||
@Autowired
|
||||
private DruidDataSource dataSource;
|
||||
|
||||
@Test
|
||||
public void testValidateFail() throws Exception {
|
||||
assertEquals(0, HostAndPortHolder.getInstance().getBlacklistSize());
|
||||
dataSource.setValidationQuery("select xxx from foo");
|
||||
Thread.sleep(20 * 1000);
|
||||
assertTrue(HostAndPortHolder.getInstance().getBlacklistSize() > 0);
|
||||
assertTrue(dataSource.isTestOnBorrow());
|
||||
assertTrue(dataSource.isTestOnReturn());
|
||||
|
||||
dataSource.setValidationQuery(null);
|
||||
Thread.sleep(20 * 1000);
|
||||
assertEquals(0, HostAndPortHolder.getInstance().getBlacklistSize());
|
||||
assertFalse(dataSource.isTestOnBorrow());
|
||||
assertFalse(dataSource.isTestOnReturn());
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,14 @@ import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Test class for JdbcUrlHostAndPortReplaceFilter
|
||||
*
|
||||
* @author DigitalSonic
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:com/alibaba/druid/filter/url/dataSource.xml")
|
||||
public class JdbcUrlHostAndPortReplaceFilterTest {
|
||||
@@ -46,5 +52,4 @@ public class JdbcUrlHostAndPortReplaceFilterTest {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,8 +9,11 @@
|
||||
default-lazy-init="false">
|
||||
|
||||
<tx:annotation-driven />
|
||||
<bean id="url-filter" class="com.alibaba.druid.filter.url.JdbcUrlHostAndPortReplaceFilter" init-method="init">
|
||||
<bean id="url-filter" class="com.alibaba.druid.filter.url.JdbcUrlHostAndPortReplaceFilter"
|
||||
init-method="init" destroy-method="close">
|
||||
<property name="file" value="/com/alibaba/druid/filter/url/datasource.properties" />
|
||||
<property name="healthCheckIntervalSeconds" value="10" />
|
||||
<property name="modifyTestFlags" value="true" />
|
||||
</bean>
|
||||
|
||||
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
|
||||
|
||||
Reference in New Issue
Block a user