开篇
- DruidDataSourceFactory通过createDataSource方法创建DruidDataSource对象并通过config方法设置DruidDataSource的属性。
- DruidDataSource通过父类DruidAbstractDataSource创建ReentrantLock lock作为DruidDataSource的锁,Condition notEmpty 作为DruidDataSource的非空信号,Condition empty作为DruidDataSource的空信号。
初始化流程
- Druid所有链接都是CreateConnectionThread创建出来的
- Druid在初始化的时候,会初始化三个内容:定时调度的DestoryTask、一直运行的CreateConnectionThread、一直运行的DestoryConnectionThread, DestoryConnectionThread是用来逐出空闲线程的。
- init在Datasource初始化的时候并不会执行,是在第一次获取getConnection执行的。
源码分析
public class DruidDataSourceFactory implements ObjectFactory {
public final static String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
public final static String PROP_DEFAULTREADONLY = "defaultReadOnly";
public final static String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
public final static String PROP_DEFAULTCATALOG = "defaultCatalog";
public final static String PROP_DRIVERCLASSNAME = "driverClassName";
public final static String PROP_MAXACTIVE = "maxActive";
public final static String PROP_MAXIDLE = "maxIdle";
public final static String PROP_MINIDLE = "minIdle";
public final static String PROP_INITIALSIZE = "initialSize";
public final static String PROP_MAXWAIT = "maxWait";
public final static String PROP_TESTONBORROW = "testOnBorrow";
public final static String PROP_TESTONRETURN = "testOnReturn";
public final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
public final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
public final static String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
public final static String PROP_PHY_TIMEOUT_MILLIS = "phyTimeoutMillis";
public final static String PROP_TESTWHILEIDLE = "testWhileIdle";
public final static String PROP_PASSWORD = "password";
public final static String PROP_URL = "url";
public final static String PROP_USERNAME = "username";
public final static String PROP_VALIDATIONQUERY = "validationQuery";
public final static String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout";
public final static String PROP_INITCONNECTIONSQLS = "initConnectionSqls";
public final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
public final static String PROP_REMOVEABANDONED = "removeAbandoned";
public final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
public final static String PROP_LOGABANDONED = "logAbandoned";
public final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
public final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
public final static String PROP_CONNECTIONPROPERTIES = "connectionProperties";
public final static String PROP_FILTERS = "filters";
public final static String PROP_EXCEPTION_SORTER = "exceptionSorter";
public final static String PROP_EXCEPTION_SORTER_CLASS_NAME = "exception-sorter-class-name";
public final static String PROP_NAME = "name";
public final static String PROP_INIT = "init";
public static DataSource createDataSource(Map properties) throws Exception {
// 创建DruidDataSource对象
DruidDataSource dataSource = new DruidDataSource();
// 设置DruidDataSource的属性
config(dataSource, properties);
return dataSource;
}
@SuppressWarnings({"deprecation", "rawtypes"})
public static void config(DruidDataSource dataSource, Map<?, ?> properties) throws SQLException {
String value = null;
value = (String) properties.get(PROP_DEFAULTAUTOCOMMIT);
if (value != null) {
dataSource.setDefaultAutoCommit(Boolean.valueOf(value).booleanValue());
}
value = (String) properties.get(PROP_DEFAULTREADONLY);
if (value != null) {
dataSource.setDefaultReadOnly(Boolean.valueOf(value).booleanValue());
}
value = (String) properties.get(PROP_DEFAULTTRANSACTIONISOLATION);
if (value != null) {
int level = UNKNOWN_TRANSACTIONISOLATION;
if ("NONE".equalsIgnoreCase(value)) {
level = Connection.TRANSACTION_NONE;
} else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
level = Connection.TRANSACTION_READ_COMMITTED;
} else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
level = Connection.TRANSACTION_READ_UNCOMMITTED;
} else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
level = Connection.TRANSACTION_REPEATABLE_READ;
} else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
level = Connection.TRANSACTION_SERIALIZABLE;
} else {
try {
level = Integer.parseInt(value);
} catch (NumberFormatException e) {
LOG.error("Could not parse defaultTransactionIsolation: " + value);
LOG.error("WARNING: defaultTransactionIsolation not set");
LOG.error("using default value of database driver");
level = UNKNOWN_TRANSACTIONISOLATION;
}
}
dataSource.setDefaultTransactionIsolation(level);
}
value = (String) properties.get(PROP_DEFAULTCATALOG);
if (value != null) {
dataSource.setDefaultCatalog(value);
}
value = (String) properties.get(PROP_DRIVERCLASSNAME);
if (value != null) {
dataSource.setDriverClassName(value);
}
value = (String) properties.get(PROP_MAXACTIVE);
if (value != null) {
dataSource.setMaxActive(Integer.parseInt(value));
}
value = (String) properties.get(PROP_MAXIDLE);
if (value != null) {
dataSource.setMaxIdle(Integer.parseInt(value));
}
value = (String) properties.get(PROP_MINIDLE);
if (value != null) {
dataSource.setMinIdle(Integer.parseInt(value));
}
value = (String) properties.get(PROP_INITIALSIZE);
if (value != null) {
dataSource.setInitialSize(Integer.parseInt(value));
}
value = (String) properties.get(PROP_MAXWAIT);
if (value != null) {
dataSource.setMaxWait(Long.parseLong(value));
}
value = (String) properties.get(PROP_TESTONBORROW);
if (value != null) {
dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
}
value = (String) properties.get(PROP_TESTONRETURN);
if (value != null) {
dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue());
}
value = (String) properties.get(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
if (value != null) {
dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
}
value = (String) properties.get(PROP_NUMTESTSPEREVICTIONRUN);
if (value != null) {
dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
}
value = (String) properties.get(PROP_MINEVICTABLEIDLETIMEMILLIS);
if (value != null) {
dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
}
value = (String) properties.get(PROP_PHY_TIMEOUT_MILLIS);
if (value != null) {
dataSource.setPhyTimeoutMillis(Long.parseLong(value));
}
value = (String) properties.get(PROP_TESTWHILEIDLE);
if (value != null) {
dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
}
value = (String) properties.get(PROP_PASSWORD);
if (value != null) {
dataSource.setPassword(value);
}
value = (String) properties.get(PROP_URL);
if (value != null) {
dataSource.setUrl(value);
}
value = (String) properties.get(PROP_USERNAME);
if (value != null) {
dataSource.setUsername(value);
}
value = (String) properties.get(PROP_VALIDATIONQUERY);
if (value != null) {
dataSource.setValidationQuery(value);
}
value = (String) properties.get(PROP_VALIDATIONQUERY_TIMEOUT);
if (value != null) {
dataSource.setValidationQueryTimeout(Integer.parseInt(value));
}
value = (String) properties.get(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
if (value != null) {
dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
}
value = (String) properties.get(PROP_REMOVEABANDONED);
if (value != null) {
dataSource.setRemoveAbandoned(Boolean.valueOf(value).booleanValue());
}
value = (String) properties.get(PROP_REMOVEABANDONEDTIMEOUT);
if (value != null) {
dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
}
value = (String) properties.get(PROP_LOGABANDONED);
if (value != null) {
dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue());
}
value = (String) properties.get(PROP_POOLPREPAREDSTATEMENTS);
if (value != null) {
boolean poolPreparedStatements = Boolean.valueOf(value).booleanValue();
dataSource.setPoolPreparedStatements(poolPreparedStatements);
if (poolPreparedStatements) {
value = (String) properties.get(PROP_MAXOPENPREPAREDSTATEMENTS);
if (value != null) {
dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
}
}
}
value = (String) properties.get(PROP_FILTERS);
if (value != null) {
dataSource.setFilters(value);
}
value = (String) properties.get(PROP_EXCEPTION_SORTER);
if (value != null) {
dataSource.setExceptionSorter(value);
}
value = (String) properties.get(PROP_EXCEPTION_SORTER_CLASS_NAME);
if (value != null) {
dataSource.setExceptionSorter(value);
}
value = (String) properties.get(PROP_INITCONNECTIONSQLS);
if (value != null) {
StringTokenizer tokenizer = new StringTokenizer(value, ";");
dataSource.setConnectionInitSqls(Collections.list(tokenizer));
}
value = (String) properties.get(PROP_CONNECTIONPROPERTIES);
if (value != null) {
dataSource.setConnectionProperties(value);
}
{
Properties dataSourceProperties = null;
for (Map.Entry entry : properties.entrySet()) {
String entryKey = (String) entry.getKey();
if (entryKey.startsWith("druid.")) {
if (dataSourceProperties == null) {
dataSourceProperties = new Properties();
}
String entryValue = (String) entry.getValue();
dataSourceProperties.put(entryKey, entryValue);
}
}
if (dataSourceProperties != null) {
dataSource.configFromPropety(dataSourceProperties);
}
}
// 执行DruidDataSource的 init 操作
value = (String) properties.get(PROP_INIT);
if ("true".equals(value)) {
dataSource.init();
}
}
}
- DruidDataSourceFactory通过createDataSource创建DruidDataSource。
- DruidDataSourceFactory通过config进行参数设置,最后执行DruidDataSource的init方法进行初始化。
public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource, MBeanRegistration {
private final static Log LOG = LogFactory.getLog(DruidDataSource.class);
private static final long serialVersionUID = 1L;
// stats
private volatile long recycleErrorCount = 0L;
private long connectCount = 0L;
private long closeCount = 0L;
private volatile long connectErrorCount = 0L;
private long recycleCount = 0L;
private long removeAbandonedCount = 0L;
private long notEmptyWaitCount = 0L;
private long notEmptySignalCount = 0L;
private long notEmptyWaitNanos = 0L;
private int keepAliveCheckCount = 0;
private int activePeak = 0;
private long activePeakTime = 0;
private int poolingPeak = 0;
private long poolingPeakTime = 0;
// store
private volatile DruidConnectionHolder[] connections;
private int poolingCount = 0;
private int activeCount = 0;
private volatile long discardCount = 0;
private int notEmptyWaitThreadCount = 0;
private int notEmptyWaitThreadPeak = 0;
//
private DruidConnectionHolder[] evictConnections;
private DruidConnectionHolder[] keepAliveConnections;
// threads
private volatile ScheduledFuture<?> destroySchedulerFuture;
private DestroyTask destroyTask;
private volatile Future<?> createSchedulerFuture;
private CreateConnectionThread createConnectionThread;
private DestroyConnectionThread destroyConnectionThread;
private LogStatsThread logStatsThread;
private int createTaskCount;
private volatile long createTaskIdSeed = 1L;
private long[] createTasks;
private final CountDownLatch initedLatch = new CountDownLatch(2);
private volatile boolean enable = true;
private boolean resetStatEnable = true;
private volatile long resetCount = 0L;
private String initStackTrace;
private volatile boolean closing = false;
private volatile boolean closed = false;
private long closeTimeMillis = -1L;
protected JdbcDataSourceStat dataSourceStat;
private boolean useGlobalDataSourceStat = false;
private boolean mbeanRegistered = false;
public static ThreadLocal<Long> waitNanosLocal = new ThreadLocal<Long>();
private boolean logDifferentThread = true;
private volatile boolean keepAlive = false;
private boolean asyncInit = false;
protected boolean killWhenSocketReadTimeout = false;
private static List<Filter> autoFilters = null;
private boolean loadSpifilterSkip = false;
private volatile DataSourceDisableException disableException = null;
protected static final AtomicLongFieldUpdater<DruidDataSource> recycleErrorCountUpdater
= AtomicLongFieldUpdater.newUpdater(DruidDataSource.class, "recycleErrorCount");
protected static final AtomicLongFieldUpdater<DruidDataSource> connectErrorCountUpdater
= AtomicLongFieldUpdater.newUpdater(DruidDataSource.class, "connectErrorCount");
protected static final AtomicLongFieldUpdater<DruidDataSource> resetCountUpdater
= AtomicLongFieldUpdater.newUpdater(DruidDataSource.class, "resetCount");
protected static final AtomicLongFieldUpdater<DruidDataSource> createTaskIdSeedUpdater
= AtomicLongFieldUpdater.newUpdater(DruidDataSource.class, "createTaskIdSeed");
public DruidDataSource(){
this(false);
}
public DruidDataSource(boolean fairLock){
// 父类DruidAbstractDataSource的构造函数初始化锁
super(fairLock);
// 通过System.getProperties()设置配置信息
configFromPropety(System.getProperties());
}
public void configFromPropety(Properties properties) {
{
String property = properties.getProperty("druid.name");
if (property != null) {
this.setName(property);
}
}
{
String property = properties.getProperty("druid.url");
if (property != null) {
this.setUrl(property);
}
}
{
String property = properties.getProperty("druid.username");
if (property != null) {
this.setUsername(property);
}
}
{
String property = properties.getProperty("druid.password");
if (property != null) {
this.setPassword(property);
}
}
{
Boolean value = getBoolean(properties, "druid.testWhileIdle");
if (value != null) {
this.testWhileIdle = value;
}
}
{
Boolean value = getBoolean(properties, "druid.testOnBorrow");
if (value != null) {
this.testOnBorrow = value;
}
}
{
String property = properties.getProperty("druid.validationQuery");
if (property != null && property.length() > 0) {
this.setValidationQuery(property);
}
}
{
Boolean value = getBoolean(properties, "druid.useGlobalDataSourceStat");
if (value != null) {
this.setUseGlobalDataSourceStat(value);
}
}
{
Boolean value = getBoolean(properties, "druid.useGloalDataSourceStat"); // compatible for early versions
if (value != null) {
this.setUseGlobalDataSourceStat(value);
}
}
{
Boolean value = getBoolean(properties, "druid.asyncInit"); // compatible for early versions
if (value != null) {
this.setAsyncInit(value);
}
}
{
String property = properties.getProperty("druid.filters");
if (property != null && property.length() > 0) {
try {
this.setFilters(property);
} catch (SQLException e) {
LOG.error("setFilters error", e);
}
}
}
{
String property = properties.getProperty(Constants.DRUID_TIME_BETWEEN_LOG_STATS_MILLIS);
if (property != null && property.length() > 0) {
try {
long value = Long.parseLong(property);
this.setTimeBetweenLogStatsMillis(value);
} catch (NumberFormatException e) {
LOG.error("illegal property '" + Constants.DRUID_TIME_BETWEEN_LOG_STATS_MILLIS + "'", e);
}
}
}
{
String property = properties.getProperty(Constants.DRUID_STAT_SQL_MAX_SIZE);
if (property != null && property.length() > 0) {
try {
int value = Integer.parseInt(property);
if (dataSourceStat != null) {
dataSourceStat.setMaxSqlSize(value);
}
} catch (NumberFormatException e) {
LOG.error("illegal property '" + Constants.DRUID_STAT_SQL_MAX_SIZE + "'", e);
}
}
}
{
Boolean value = getBoolean(properties, "druid.clearFiltersEnable");
if (value != null) {
this.setClearFiltersEnable(value);
}
}
{
Boolean value = getBoolean(properties, "druid.resetStatEnable");
if (value != null) {
this.setResetStatEnable(value);
}
}
{
String property = properties.getProperty("druid.notFullTimeoutRetryCount");
if (property != null && property.length() > 0) {
try {
int value = Integer.parseInt(property);
this.setNotFullTimeoutRetryCount(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.notFullTimeoutRetryCount'", e);
}
}
}
{
String property = properties.getProperty("druid.timeBetweenEvictionRunsMillis");
if (property != null && property.length() > 0) {
try {
long value = Long.parseLong(property);
this.setTimeBetweenEvictionRunsMillis(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.timeBetweenEvictionRunsMillis'", e);
}
}
}
{
String property = properties.getProperty("druid.maxWaitThreadCount");
if (property != null && property.length() > 0) {
try {
int value = Integer.parseInt(property);
this.setMaxWaitThreadCount(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.maxWaitThreadCount'", e);
}
}
}
{
String property = properties.getProperty("druid.maxWait");
if (property != null && property.length() > 0) {
try {
int value = Integer.parseInt(property);
this.setMaxWait(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.maxWait'", e);
}
}
}
{
Boolean value = getBoolean(properties, "druid.failFast");
if (value != null) {
this.setFailFast(value);
}
}
{
String property = properties.getProperty("druid.phyTimeoutMillis");
if (property != null && property.length() > 0) {
try {
long value = Long.parseLong(property);
this.setPhyTimeoutMillis(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.phyTimeoutMillis'", e);
}
}
}
{
String property = properties.getProperty("druid.phyMaxUseCount");
if (property != null && property.length() > 0) {
try {
long value = Long.parseLong(property);
this.setPhyMaxUseCount(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.phyMaxUseCount'", e);
}
}
}
{
String property = properties.getProperty("druid.minEvictableIdleTimeMillis");
if (property != null && property.length() > 0) {
try {
long value = Long.parseLong(property);
this.setMinEvictableIdleTimeMillis(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.minEvictableIdleTimeMillis'", e);
}
}
}
{
String property = properties.getProperty("druid.maxEvictableIdleTimeMillis");
if (property != null && property.length() > 0) {
try {
long value = Long.parseLong(property);
this.setMaxEvictableIdleTimeMillis(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.maxEvictableIdleTimeMillis'", e);
}
}
}
{
Boolean value = getBoolean(properties, "druid.keepAlive");
if (value != null) {
this.setKeepAlive(value);
}
}
{
String property = properties.getProperty("druid.keepAliveBetweenTimeMillis");
if (property != null && property.length() > 0) {
try {
long value = Long.parseLong(property);
this.setKeepAliveBetweenTimeMillis(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.keepAliveBetweenTimeMillis'", e);
}
}
}
{
Boolean value = getBoolean(properties, "druid.poolPreparedStatements");
if (value != null) {
this.setPoolPreparedStatements0(value);
}
}
{
Boolean value = getBoolean(properties, "druid.initVariants");
if (value != null) {
this.setInitVariants(value);
}
}
{
Boolean value = getBoolean(properties, "druid.initGlobalVariants");
if (value != null) {
this.setInitGlobalVariants(value);
}
}
{
Boolean value = getBoolean(properties, "druid.useUnfairLock");
if (value != null) {
this.setUseUnfairLock(value);
}
}
{
String property = properties.getProperty("druid.driverClassName");
if (property != null) {
this.setDriverClassName(property);
}
}
{
String property = properties.getProperty("druid.initialSize");
if (property != null && property.length() > 0) {
try {
int value = Integer.parseInt(property);
this.setInitialSize(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.initialSize'", e);
}
}
}
{
String property = properties.getProperty("druid.minIdle");
if (property != null && property.length() > 0) {
try {
int value = Integer.parseInt(property);
this.setMinIdle(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.minIdle'", e);
}
}
}
{
String property = properties.getProperty("druid.maxActive");
if (property != null && property.length() > 0) {
try {
int value = Integer.parseInt(property);
this.setMaxActive(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.maxActive'", e);
}
}
}
{
Boolean value = getBoolean(properties, "druid.killWhenSocketReadTimeout");
if (value != null) {
setKillWhenSocketReadTimeout(value);
}
}
{
String property = properties.getProperty("druid.connectProperties");
if (property != null) {
this.setConnectionProperties(property);
}
}
{
String property = properties.getProperty("druid.maxPoolPreparedStatementPerConnectionSize");
if (property != null && property.length() > 0) {
try {
int value = Integer.parseInt(property);
this.setMaxPoolPreparedStatementPerConnectionSize(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.maxPoolPreparedStatementPerConnectionSize'", e);
}
}
}
{
String property = properties.getProperty("druid.initConnectionSqls");
if (property != null && property.length() > 0) {
try {
StringTokenizer tokenizer = new StringTokenizer(property, ";");
setConnectionInitSqls(Collections.list(tokenizer));
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.initConnectionSqls'", e);
}
}
}
{
String property = System.getProperty("druid.load.spifilter.skip");
if (property != null && !"false".equals(property)) {
loadSpifilterSkip = true;
}
}
}
}
- DruidDataSource的构造函数通过父类DruidAbstractDataSource初始化锁。
- DruidDataSource的构造函数通过configFromPropety初始化配置信息。
public abstract class DruidAbstractDataSource extends WrapperAdapter implements DruidAbstractDataSourceMBean, DataSource, DataSourceProxy, Serializable {
private static final long serialVersionUID = 1L;
private final static Log LOG = LogFactory.getLog(DruidAbstractDataSource.class);
public final static int DEFAULT_INITIAL_SIZE = 0;
public final static int DEFAULT_MAX_ACTIVE_SIZE = 8;
public final static int DEFAULT_MAX_IDLE = 8;
public final static int DEFAULT_MIN_IDLE = 0;
public final static int DEFAULT_MAX_WAIT = -1;
public final static String DEFAULT_VALIDATION_QUERY = null; //
public final static boolean DEFAULT_TEST_ON_BORROW = false;
public final static boolean DEFAULT_TEST_ON_RETURN = false;
public final static boolean DEFAULT_WHILE_IDLE = true;
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = 60 * 1000L;
public static final long DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS = 500;
public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L;
public static final long DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 60L * 7;
public static final long DEFAULT_PHY_TIMEOUT_MILLIS = -1;
protected volatile boolean defaultAutoCommit = true;
protected volatile Boolean defaultReadOnly;
protected volatile Integer defaultTransactionIsolation;
protected volatile String defaultCatalog = null;
protected String name;
protected volatile String username;
protected volatile String password;
protected volatile String jdbcUrl;
protected volatile String driverClass;
protected volatile ClassLoader driverClassLoader;
protected volatile Properties connectProperties = new Properties();
protected volatile PasswordCallback passwordCallback;
protected volatile NameCallback userCallback;
protected volatile int initialSize = DEFAULT_INITIAL_SIZE;
protected volatile int maxActive = DEFAULT_MAX_ACTIVE_SIZE;
protected volatile int minIdle = DEFAULT_MIN_IDLE;
protected volatile int maxIdle = DEFAULT_MAX_IDLE;
protected volatile long maxWait = DEFAULT_MAX_WAIT;
protected int notFullTimeoutRetryCount = 0;
protected volatile String validationQuery = DEFAULT_VALIDATION_QUERY;
protected volatile int validationQueryTimeout = -1;
protected volatile boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;
protected volatile boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
protected volatile boolean testWhileIdle = DEFAULT_WHILE_IDLE;
protected volatile boolean poolPreparedStatements = false;
protected volatile boolean sharePreparedStatements = false;
protected volatile int maxPoolPreparedStatementPerConnectionSize = 10;
protected volatile boolean inited = false;
protected volatile boolean initExceptionThrow = true;
protected PrintWriter logWriter = new PrintWriter(System.out);
protected List<Filter> filters = new CopyOnWriteArrayList<Filter>();
private boolean clearFiltersEnable = true;
protected volatile ExceptionSorter exceptionSorter = null;
protected Driver driver;
protected volatile int queryTimeout;
protected volatile int transactionQueryTimeout;
protected long createTimespan;
protected volatile int maxWaitThreadCount = -1;
protected volatile boolean accessToUnderlyingConnectionAllowed = true;
protected volatile long timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
protected volatile int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
protected volatile long minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
protected volatile long maxEvictableIdleTimeMillis = DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS;
protected volatile long keepAliveBetweenTimeMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS * 2;
protected volatile long phyTimeoutMillis = DEFAULT_PHY_TIMEOUT_MILLIS;
protected volatile long phyMaxUseCount = -1;
protected volatile boolean removeAbandoned;
protected volatile long removeAbandonedTimeoutMillis = 300 * 1000;
protected volatile boolean logAbandoned;
protected volatile int maxOpenPreparedStatements = -1;
protected volatile List<String> connectionInitSqls;
protected volatile String dbType;
protected volatile long timeBetweenConnectErrorMillis = DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS;
protected volatile ValidConnectionChecker validConnectionChecker = null;
protected final Map<DruidPooledConnection, Object> activeConnections = new IdentityHashMap<DruidPooledConnection, Object>();
protected final static Object PRESENT = new Object();
protected long id;
protected int connectionErrorRetryAttempts = 1;
protected boolean breakAfterAcquireFailure = false;
protected long transactionThresholdMillis = 0L;
protected final Date createdTime = new Date();
protected Date initedTime;
protected volatile long errorCount = 0L;
protected volatile long dupCloseCount = 0L;
protected volatile long startTransactionCount = 0L;
protected volatile long commitCount = 0L;
protected volatile long rollbackCount = 0L;
protected volatile long cachedPreparedStatementHitCount = 0L;
protected volatile long preparedStatementCount = 0L;
protected volatile long closedPreparedStatementCount = 0L;
protected volatile long cachedPreparedStatementCount = 0L;
protected volatile long cachedPreparedStatementDeleteCount = 0L;
protected volatile long cachedPreparedStatementMissCount = 0L;
final static AtomicLongFieldUpdater<DruidAbstractDataSource> errorCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "errorCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> dupCloseCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "dupCloseCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> startTransactionCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "startTransactionCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> commitCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "commitCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> rollbackCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "rollbackCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> cachedPreparedStatementHitCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "cachedPreparedStatementHitCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> preparedStatementCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "preparedStatementCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> closedPreparedStatementCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "closedPreparedStatementCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> cachedPreparedStatementCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "cachedPreparedStatementCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> cachedPreparedStatementDeleteCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "cachedPreparedStatementDeleteCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> cachedPreparedStatementMissCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "cachedPreparedStatementMissCount");
protected final Histogram transactionHistogram = new Histogram(1,
10,
100,
1000,
10 * 1000,
100 * 1000);
private boolean dupCloseLogEnable = false;
private ObjectName objectName;
protected volatile long executeCount = 0L;
protected volatile long executeQueryCount = 0L;
protected volatile long executeUpdateCount = 0L;
protected volatile long executeBatchCount = 0L;
final static AtomicLongFieldUpdater<DruidAbstractDataSource> executeQueryCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "executeQueryCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> executeUpdateCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "executeUpdateCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> executeBatchCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "executeBatchCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> executeCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "executeCount");
protected volatile Throwable createError;
protected volatile Throwable lastError;
protected volatile long lastErrorTimeMillis;
protected volatile Throwable lastCreateError;
protected volatile long lastCreateErrorTimeMillis;
protected volatile long lastCreateStartTimeMillis;
protected boolean isOracle = false;
protected boolean isMySql = false;
protected boolean useOracleImplicitCache = true;
protected ReentrantLock lock;
protected Condition notEmpty;
protected Condition empty;
protected ReentrantLock activeConnectionLock = new ReentrantLock();
protected volatile int createErrorCount = 0;
protected volatile int creatingCount = 0;
protected volatile int directCreateCount = 0;
protected volatile long createCount = 0L;
protected volatile long destroyCount = 0L;
protected volatile long createStartNanos = 0L;
final static AtomicIntegerFieldUpdater<DruidAbstractDataSource> createErrorCountUpdater = AtomicIntegerFieldUpdater.newUpdater(DruidAbstractDataSource.class, "createErrorCount");
final static AtomicIntegerFieldUpdater<DruidAbstractDataSource> creatingCountUpdater = AtomicIntegerFieldUpdater.newUpdater(DruidAbstractDataSource.class, "creatingCount");
final static AtomicIntegerFieldUpdater<DruidAbstractDataSource> directCreateCountUpdater = AtomicIntegerFieldUpdater.newUpdater(DruidAbstractDataSource.class, "directCreateCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> createCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "createCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> destroyCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "destroyCount");
final static AtomicLongFieldUpdater<DruidAbstractDataSource> createStartNanosUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "createStartNanos");
private Boolean useUnfairLock = null;
private boolean useLocalSessionState = true;
protected long timeBetweenLogStatsMillis;
protected DruidDataSourceStatLogger statLogger = new DruidDataSourceStatLoggerImpl();
private boolean asyncCloseConnectionEnable = false;
protected int maxCreateTaskCount = 3;
protected boolean failFast = false;
protected volatile int failContinuous = 0;
protected volatile long failContinuousTimeMillis = 0L;
protected ScheduledExecutorService destroyScheduler;
protected ScheduledExecutorService createScheduler;
final static AtomicLongFieldUpdater<DruidAbstractDataSource> failContinuousTimeMillisUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "failContinuousTimeMillis");
final static AtomicIntegerFieldUpdater<DruidAbstractDataSource> failContinuousUpdater = AtomicIntegerFieldUpdater.newUpdater(DruidAbstractDataSource.class, "failContinuous");
protected boolean initVariants = false;
protected boolean initGlobalVariants = false;
protected volatile boolean onFatalError = false;
protected volatile int onFatalErrorMaxActive = 0;
protected volatile int fatalErrorCount = 0;
protected volatile int fatalErrorCountLastShrink = 0;
protected volatile long lastFatalErrorTimeMillis = 0;
protected volatile String lastFatalErrorSql = null;
protected volatile Throwable lastFatalError = null;
public DruidAbstractDataSource(boolean lockFair){
lock = new ReentrantLock(lockFair);
notEmpty = lock.newCondition();
empty = lock.newCondition();
}
}
- ReentrantLock lock:创建Connection的线程、销毁的线程、获取连接的线程,需要获得重入锁,才可以对内部数据进行操作,当然只是在需要的地方加锁。
- Condition notEmpty:如果获取连接的线程发现连接池空了,一方面会唤醒empty,另外一方面自己会调用notEmpty.await()进入等待,由CreateConnectionThread唤醒,或者其他线程释放连接时唤醒。
- Condition empty:CreateConnectionThread只有在连接池不够用的情况下才会创建,否则调用empty.await()挂起线程。如果获取连接的线程发现连接全部被拿走了,则会调用empty.signal()唤醒CreateConnectionThread创建连接,同时也会调用notEmpty.await()进入等待。
public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource, MBeanRegistration {
public void init() throws SQLException {
// 由volatile修饰的inited,每次获取链接也会调用 init()方法
if (inited) {
return;
}
// bug fixed for dead lock, for issue #2980
DruidDriver.getInstance();
final ReentrantLock lock = this.lock;
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
throw new SQLException("interrupt", e);
}
boolean init = false;
try {
if (inited) {
return;
}
initStackTrace = Utils.toString(Thread.currentThread().getStackTrace());
this.id = DruidDriver.createDataSourceId();
if (this.id > 1) {
long delta = (this.id - 1) * 100000;
this.connectionIdSeedUpdater.addAndGet(this, delta);
this.statementIdSeedUpdater.addAndGet(this, delta);
this.resultSetIdSeedUpdater.addAndGet(this, delta);
this.transactionIdSeedUpdater.addAndGet(this, delta);
}
if (this.jdbcUrl != null) {
this.jdbcUrl = this.jdbcUrl.trim();
initFromWrapDriverUrl();
}
// 初始化filters对象
for (Filter filter : filters) {
filter.init(this);
}
if (this.dbType == null || this.dbType.length() == 0) {
this.dbType = JdbcUtils.getDbType(jdbcUrl, null);
}
if (JdbcConstants.MYSQL.equals(this.dbType)
|| JdbcConstants.MARIADB.equals(this.dbType)
|| JdbcConstants.ALIYUN_ADS.equals(this.dbType)) {
boolean cacheServerConfigurationSet = false;
if (this.connectProperties.containsKey("cacheServerConfiguration")) {
cacheServerConfigurationSet = true;
} else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) {
cacheServerConfigurationSet = true;
}
if (cacheServerConfigurationSet) {
this.connectProperties.put("cacheServerConfiguration", "true");
}
}
// 省略参数检查的代码
if (this.driverClass != null) {
this.driverClass = driverClass.trim();
}
initFromSPIServiceLoader();
if (this.driver == null) {
if (this.driverClass == null || this.driverClass.isEmpty()) {
this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl);
}
if (MockDriver.class.getName().equals(driverClass)) {
driver = MockDriver.instance;
} else {
if (jdbcUrl == null && (driverClass == null || driverClass.length() == 0)) {
throw new SQLException("url not set");
}
driver = JdbcUtils.createDriver(driverClassLoader, driverClass);
}
} else {
if (this.driverClass == null) {
this.driverClass = driver.getClass().getName();
}
}
initCheck();
initExceptionSorter();
initValidConnectionChecker();
validationQueryCheck();
if (isUseGlobalDataSourceStat()) {
dataSourceStat = JdbcDataSourceStat.getGlobal();
if (dataSourceStat == null) {
dataSourceStat = new JdbcDataSourceStat("Global", "Global", this.dbType);
JdbcDataSourceStat.setGlobal(dataSourceStat);
}
if (dataSourceStat.getDbType() == null) {
dataSourceStat.setDbType(this.dbType);
}
} else {
dataSourceStat = new JdbcDataSourceStat(this.name, this.jdbcUrl, this.dbType, this.connectProperties);
}
dataSourceStat.setResetStatEnable(this.resetStatEnable);
connections = new DruidConnectionHolder[maxActive];
evictConnections = new DruidConnectionHolder[maxActive];
keepAliveConnections = new DruidConnectionHolder[maxActive];
SQLException connectError = null;
if (createScheduler != null && asyncInit) {
for (int i = 0; i < initialSize; ++i) {
submitCreateTask(true);
}
} else if (!asyncInit) {
// 初始化连接数
while (poolingCount < initialSize) {
try {
// 创建连接
PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
connections[poolingCount++] = holder;
} catch (SQLException ex) {
LOG.error("init datasource error, url: " + this.getUrl(), ex);
if (initExceptionThrow) {
connectError = ex;
break;
} else {
Thread.sleep(3000);
}
}
}
if (poolingCount > 0) {
poolingPeak = poolingCount;
poolingPeakTime = System.currentTimeMillis();
}
}
// 创建各类线程,包括连接创建线程和连接销毁线程
createAndLogThread();
createAndStartCreatorThread();
createAndStartDestroyThread();
// 等待线程启动完成
initedLatch.await();
init = true;
initedTime = new Date();
registerMbean();
if (keepAlive) {
// async fill to minIdle
if (createScheduler != null) {
for (int i = 0; i < minIdle; ++i) {
submitCreateTask(true);
}
} else {
this.emptySignal();
}
}
} catch (SQLException e) {
throw e;
} finally {
inited = true;
lock.unlock();
}
}
}
}
- 加载数据库驱动Driver
- 根据不同的数据库,实例化ExceptionSorter,主要的api就是isExceptionFatal(SQLException e),用于判断是否是Fatal级别的异常。
- 初始化连接检测器,不同数据库的实现不一样,比如mysql是调用pingInternal检测连接是否OK。ValidConnectionChecker在获取连接、回收连接的时候会用到
- 初始化JdbcDataSourceStat,主要目的是做监控。
- 初始化connections、evictConnections、keepAliveConnections数组,分别用于存放可被获取的连接池、待清理的连接池、存活的连接池,数组的大小都是maxActive。
- 初始化initialSize个Connection。
- 开启LogStatsThread线程,用于定期打印DruidDataSource的一些数据,默认是不开启的,需要开启的话只需要设置timeBetweenLogStatsMillis指定打印的时间周期,log步骤需要获取主锁,建议时间不要设得太短。
- 创建CreateConnectionThread线程,druid内部默认使用一个线程异步地创建连接,当然可以指定createScheduler线程池,开启多个线程创建连接,但是请把keepAlive设为true,否则不会开启异步线程创建连接。
- 创建DestroyConnectionThread线程,定期扫描连接池内过期的连接,如果想对连接池外面正在使用的连接也进行清理的话,需要指定removeAbandoned为true,清理线程会判断连接是否正在使用,是否超过了清理时间而进行清理。
参考