From e64d66460cdd76f23f0441d97b38eb464f610af2 Mon Sep 17 00:00:00 2001 From: wenshao Date: Wed, 11 May 2011 14:15:38 +0000 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81JNDI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://code.alibabatech.com/svn/druid/trunk@16 b9813039-fb51-4c41-a8b9-e21c2acb5095 --- .../druid/pool/DruidDataAbstractSource.java | 192 ++++++++-- .../druid/pool/DruidDataSourceFactory.java | 339 ++++++++++++++++-- 2 files changed, 474 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataAbstractSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataAbstractSource.java index e17cef8802..8d0eb9debb 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataAbstractSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataAbstractSource.java @@ -14,6 +14,9 @@ import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Properties; @@ -30,22 +33,32 @@ import com.alibaba.druid.proxy.jdbc.DataSourceProxy; */ public abstract class DruidDataAbstractSource implements DataSource, DataSourceProxy, Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - 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 = "SELECT 1"; - public final static boolean DEFAULT_TEST_ON_BORROW = true; - public final static boolean DEFAULT_TEST_ON_RETURN = false; - public final static boolean DEFAULT_WHILE_IDLE = false; + 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 = "SELECT 1"; + public final static boolean DEFAULT_TEST_ON_BORROW = true; + public final static boolean DEFAULT_TEST_ON_RETURN = false; + public final static boolean DEFAULT_WHILE_IDLE = false; + public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L; + public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3; - private boolean defaultAutoCommit = false; + /** + * The default value for {@link #getMinEvictableIdleTimeMillis}. + * + * @see #getMinEvictableIdleTimeMillis + * @see #setMinEvictableIdleTimeMillis + */ + public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L; + + private boolean defaultAutoCommit = false; private Boolean defaultReadOnly; private Integer defaultTransactionIsolation; - private String defaultCatalog = null; + private String defaultCatalog = null; protected String name; @@ -53,30 +66,31 @@ public abstract class DruidDataAbstractSource implements DataSource, DataSourceP protected String password; protected String jdbcUrl; protected String driverClass; - protected Properties properties = new Properties(); + protected Properties properties = new Properties(); protected PasswordCallback passwordCallback; protected NameCallback userCallback; protected ConnectionFactory connectionFactory; - protected int initialSize = DEFAULT_INITIAL_SIZE; - protected int maxActive = DEFAULT_MAX_ACTIVE_SIZE; - protected int minIdle = DEFAULT_MIN_IDLE; - protected int maxIdle = DEFAULT_MAX_IDLE; - protected long maxWait = DEFAULT_MAX_WAIT; + protected int initialSize = DEFAULT_INITIAL_SIZE; + protected int maxActive = DEFAULT_MAX_ACTIVE_SIZE; + protected int minIdle = DEFAULT_MIN_IDLE; + protected int maxIdle = DEFAULT_MAX_IDLE; + protected long maxWait = DEFAULT_MAX_WAIT; - protected String validationQuery = DEFAULT_VALIDATION_QUERY; - private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; - private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; - private boolean testWhileIdle = DEFAULT_WHILE_IDLE; - protected boolean poolPreparedStatements = false; + protected String validationQuery = DEFAULT_VALIDATION_QUERY; + protected int validationQueryTimeout = -1; + private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; + private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; + private boolean testWhileIdle = DEFAULT_WHILE_IDLE; + protected boolean poolPreparedStatements = false; - protected boolean inited = false; + protected boolean inited = false; - protected PrintWriter logWriter = new PrintWriter(System.out); + protected PrintWriter logWriter = new PrintWriter(System.out); - private final List filters = new ArrayList(); + private final List filters = new ArrayList(); protected Driver driver; @@ -86,7 +100,115 @@ public abstract class DruidDataAbstractSource implements DataSource, DataSourceP protected long createTimespan; - protected int maxWaitThreadCount = -1; + protected int maxWaitThreadCount = -1; + + protected boolean accessToUnderlyingConnectionAllowed = true; + + protected long timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; + + protected int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN; + + protected long minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + + protected boolean removeAbandoned; + + protected int removeAbandonedTimeout; + + protected boolean logAbandoned; + + protected int maxOpenPreparedStatements = -1; + + protected List connectionInitSqls; + + public void addConnectionProperty(String name, String value) { + properties.put(name, value); + } + + public Collection getConnectionInitSqls() { + Collection result = connectionInitSqls; + if (result == null) { + return Collections.emptyList(); + } + return result; + } + + public void setConnectionInitSqls(Collection connectionInitSqls) { + if ((connectionInitSqls != null) && (connectionInitSqls.size() > 0)) { + ArrayList newVal = null; + for (Iterator iterator = connectionInitSqls.iterator(); + iterator.hasNext();) { + Object o = iterator.next(); + if (o != null) { + String s = o.toString(); + if (s.trim().length() > 0) { + if (newVal == null) { + newVal = new ArrayList(); + } + newVal.add(s); + } + } + } + this.connectionInitSqls = newVal; + } else { + this.connectionInitSqls = null; + } + } + + public int getMaxOpenPreparedStatements() { + return maxOpenPreparedStatements; + } + + public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) { + this.maxOpenPreparedStatements = maxOpenPreparedStatements; + } + + public boolean isLogAbandoned() { + return logAbandoned; + } + + public void setLogAbandoned(boolean logAbandoned) { + this.logAbandoned = logAbandoned; + } + + public int getRemoveAbandonedTimeout() { + return removeAbandonedTimeout; + } + + public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { + this.removeAbandonedTimeout = removeAbandonedTimeout; + } + + public boolean isRemoveAbandoned() { + return removeAbandoned; + } + + public void setRemoveAbandoned(boolean removeAbandoned) { + this.removeAbandoned = removeAbandoned; + } + + public long getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + public int getNumTestsPerEvictionRun() { + return numTestsPerEvictionRun; + } + + public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { + this.numTestsPerEvictionRun = numTestsPerEvictionRun; + } + + public long getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } public int getMaxWaitThreadCount() { return maxWaitThreadCount; @@ -104,6 +226,22 @@ public abstract class DruidDataAbstractSource implements DataSource, DataSourceP this.validationQuery = validationQuery; } + public int getValidationQueryTimeout() { + return validationQueryTimeout; + } + + public void setValidationQueryTimeout(int validationQueryTimeout) { + this.validationQueryTimeout = validationQueryTimeout; + } + + public boolean isAccessToUnderlyingConnectionAllowed() { + return accessToUnderlyingConnectionAllowed; + } + + public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) { + this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed; + } + public boolean isTestOnBorrow() { return testOnBorrow; } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceFactory.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceFactory.java index 4f174e8fde..3e9ddc5297 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceFactory.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceFactory.java @@ -1,32 +1,311 @@ /* - * Copyright 2011 Alibaba Group. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2011 Alibaba Group. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and limitations under the + * License. */ -package com.alibaba.druid.pool; - -import java.util.Hashtable; - -import javax.naming.Context; -import javax.naming.Name; -import javax.naming.spi.ObjectFactory; - -public class DruidDataSourceFactory implements ObjectFactory { - - @Override - public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { - // TODO Auto-generated method stub - return null; - } - -} +package com.alibaba.druid.pool; + +import java.io.ByteArrayInputStream; +import java.sql.Connection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Properties; +import java.util.StringTokenizer; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.RefAddr; +import javax.naming.Reference; +import javax.naming.spi.ObjectFactory; +import javax.sql.DataSource; + +import org.apache.commons.dbcp.BasicDataSource; + +public class DruidDataSourceFactory implements ObjectFactory { + static final int UNKNOWN_TRANSACTIONISOLATION = -1; + + private final static String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit"; + private final static String PROP_DEFAULTREADONLY = "defaultReadOnly"; + private final static String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation"; + private final static String PROP_DEFAULTCATALOG = "defaultCatalog"; + private final static String PROP_DRIVERCLASSNAME = "driverClassName"; + private final static String PROP_MAXACTIVE = "maxActive"; + private final static String PROP_MAXIDLE = "maxIdle"; + private final static String PROP_MINIDLE = "minIdle"; + private final static String PROP_INITIALSIZE = "initialSize"; + private final static String PROP_MAXWAIT = "maxWait"; + private final static String PROP_TESTONBORROW = "testOnBorrow"; + private final static String PROP_TESTONRETURN = "testOnReturn"; + private final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis"; + private final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun"; + private final static String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis"; + private final static String PROP_TESTWHILEIDLE = "testWhileIdle"; + private final static String PROP_PASSWORD = "password"; + private final static String PROP_URL = "url"; + private final static String PROP_USERNAME = "username"; + private final static String PROP_VALIDATIONQUERY = "validationQuery"; + private final static String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout"; + + /** + * The property name for initConnectionSqls. The associated value String must be of the form [query;]* + * + * @since 1.3 + */ + private final static String PROP_INITCONNECTIONSQLS = "initConnectionSqls"; + private final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed"; + private final static String PROP_REMOVEABANDONED = "removeAbandoned"; + private final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout"; + private final static String PROP_LOGABANDONED = "logAbandoned"; + private final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements"; + private final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements"; + private final static String PROP_CONNECTIONPROPERTIES = "connectionProperties"; + + private final static String[] ALL_PROPERTIES = { PROP_DEFAULTAUTOCOMMIT, + PROP_DEFAULTREADONLY, PROP_DEFAULTTRANSACTIONISOLATION, PROP_DEFAULTCATALOG, PROP_DRIVERCLASSNAME, + PROP_MAXACTIVE, PROP_MAXIDLE, PROP_MINIDLE, PROP_INITIALSIZE, PROP_MAXWAIT, PROP_TESTONBORROW, + PROP_TESTONRETURN, PROP_TIMEBETWEENEVICTIONRUNSMILLIS, PROP_NUMTESTSPEREVICTIONRUN, + PROP_MINEVICTABLEIDLETIMEMILLIS, PROP_TESTWHILEIDLE, PROP_PASSWORD, PROP_URL, PROP_USERNAME, + PROP_VALIDATIONQUERY, PROP_VALIDATIONQUERY_TIMEOUT, PROP_INITCONNECTIONSQLS, + PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED, PROP_REMOVEABANDONED, PROP_REMOVEABANDONEDTIMEOUT, + PROP_LOGABANDONED, PROP_POOLPREPAREDSTATEMENTS, PROP_MAXOPENPREPAREDSTATEMENTS, PROP_CONNECTIONPROPERTIES }; + + @Override + public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) + throws Exception { + + // We only know how to deal with javax.naming.References + // that specify a class name of "javax.sql.DataSource" + if ((obj == null) || !(obj instanceof Reference)) { + return null; + } + Reference ref = (Reference) obj; + if (!"javax.sql.DataSource".equals(ref.getClassName())) { + return null; + } + + Properties properties = new Properties(); + for (int i = 0; i < ALL_PROPERTIES.length; i++) { + String propertyName = ALL_PROPERTIES[i]; + RefAddr ra = ref.get(propertyName); + if (ra != null) { + String propertyValue = ra.getContent().toString(); + properties.setProperty(propertyName, propertyValue); + } + } + + return createDataSource(properties); + } + + /** + * Creates and configures a {@link BasicDataSource} instance based on the given properties. + * + * @param properties the datasource configuration properties + * @throws Exception if an error occurs creating the data source + */ + public static DataSource createDataSource(Properties properties) throws Exception { + DruidDataSource dataSource = new DruidDataSource(); + String value = null; + + value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT); + if (value != null) { + dataSource.setDefaultAutoCommit(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_DEFAULTREADONLY); + if (value != null) { + dataSource.setDefaultReadOnly(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(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) { + System.err.println("Could not parse defaultTransactionIsolation: " + value); + System.err.println("WARNING: defaultTransactionIsolation not set"); + System.err.println("using default value of database driver"); + level = UNKNOWN_TRANSACTIONISOLATION; + } + } + dataSource.setDefaultTransactionIsolation(level); + } + + value = properties.getProperty(PROP_DEFAULTCATALOG); + if (value != null) { + dataSource.setDefaultCatalog(value); + } + + value = properties.getProperty(PROP_DRIVERCLASSNAME); + if (value != null) { + dataSource.setDriverClassName(value); + } + + value = properties.getProperty(PROP_MAXACTIVE); + if (value != null) { + dataSource.setMaxActive(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_MAXIDLE); + if (value != null) { + dataSource.setMaxIdle(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_MINIDLE); + if (value != null) { + dataSource.setMinIdle(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_INITIALSIZE); + if (value != null) { + dataSource.setInitialSize(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_MAXWAIT); + if (value != null) { + dataSource.setMaxWait(Long.parseLong(value)); + } + + value = properties.getProperty(PROP_TESTONBORROW); + if (value != null) { + dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_TESTONRETURN); + if (value != null) { + dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS); + if (value != null) { + dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value)); + } + + value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN); + if (value != null) { + dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS); + if (value != null) { + dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value)); + } + + value = properties.getProperty(PROP_TESTWHILEIDLE); + if (value != null) { + dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_PASSWORD); + if (value != null) { + dataSource.setPassword(value); + } + + value = properties.getProperty(PROP_URL); + if (value != null) { + dataSource.setUrl(value); + } + + value = properties.getProperty(PROP_USERNAME); + if (value != null) { + dataSource.setUsername(value); + } + + value = properties.getProperty(PROP_VALIDATIONQUERY); + if (value != null) { + dataSource.setValidationQuery(value); + } + + value = properties.getProperty(PROP_VALIDATIONQUERY_TIMEOUT); + if (value != null) { + dataSource.setValidationQueryTimeout(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED); + if (value != null) { + dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_REMOVEABANDONED); + if (value != null) { + dataSource.setRemoveAbandoned(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT); + if (value != null) { + dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_LOGABANDONED); + if (value != null) { + dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS); + if (value != null) { + dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS); + if (value != null) { + dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_INITCONNECTIONSQLS); + if (value != null) { + StringTokenizer tokenizer = new StringTokenizer(value, ";"); + dataSource.setConnectionInitSqls(Collections.list(tokenizer)); + } + + value = properties.getProperty(PROP_CONNECTIONPROPERTIES); + if (value != null) { + Properties p = getProperties(value); + Enumeration e = p.propertyNames(); + while (e.hasMoreElements()) { + String propertyName = (String) e.nextElement(); + dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName)); + } + } + + // DBCP-215 + // Trick to make sure that initialSize connections are created + if (dataSource.getInitialSize() > 0) { + dataSource.getLogWriter(); + } + + // Return the configured DataSource instance + return dataSource; + } + + /** + *

+ * Parse properties from the string. Format of the string must be [propertyName=property;]* + *

+ * + * @param propText + * @return Properties + * @throws Exception + */ + static private Properties getProperties(String propText) throws Exception { + Properties p = new Properties(); + if (propText != null) { + p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes())); + } + return p; + } +}