使用连接生命周期管理扩展连接池功能

来源:互联网 发布:淘宝聚划算秒杀技巧 编辑:程序博客网 时间:2024/06/05 01:11

在操作数据库连接的时候有些时候可能要要跟踪连接的生命周期,如要建立基于连接的临时表,要修改该连接中的某些连接参数(如时间的默认格式)。但是jdbc规范中没有这类规范,所以只能自己实现。
下面是通过修改commons-dbcp获得的功能.
@SuppressWarnings("unchecked")
public class BasicDataSourceExtendListenerImpl extends BasicDataSource {

 private List<ListenerConfig> listeners;

 // ------------------------------------------------------------- Properties

 /**
  * The default auto-commit state of connections created by this pool.
  */
 protected boolean defaultAutoCommit = true;

 public BasicDataSourceExtendListenerImpl(
 }

public void setListeners(List<ListenerConfig> listeners){
this.listeners = listeners;
}

 @Override
 public synchronized boolean getDefaultAutoCommit() {
  return this.defaultAutoCommit;
 }

 @Override
 public synchronized void setDefaultAutoCommit(boolean defaultAutoCommit) {
  this.defaultAutoCommit = defaultAutoCommit;
  this.restartNeeded = true;
 }

 /**
  * The default read-only state of connections created by this pool.
  */
 protected Boolean defaultReadOnly = null;

 @Override
 public synchronized boolean getDefaultReadOnly() {
  if (this.defaultReadOnly != null) {
   return this.defaultReadOnly.booleanValue();
  }
  return false;
 }

 @Override
 public synchronized void setDefaultReadOnly(boolean defaultReadOnly) {
  this.defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
  this.restartNeeded = true;
 }

 /**
  * The default TransactionIsolation state of connections created by this
  * pool.
  */
 protected int defaultTransactionIsolation = -1;

 @Override
 public synchronized int getDefaultTransactionIsolation() {
  return this.defaultTransactionIsolation;
 }

 @Override
 public synchronized void setDefaultTransactionIsolation(
   int defaultTransactionIsolation) {
  this.defaultTransactionIsolation = defaultTransactionIsolation;
  this.restartNeeded = true;
 }

 /**
  * The default "catalog" of connections created by this pool.
  */
 protected String defaultCatalog = null;

 @Override
 public synchronized String getDefaultCatalog() {
  return this.defaultCatalog;
 }

 @Override
 public synchronized void setDefaultCatalog(String defaultCatalog) {
  if ((defaultCatalog != null) && (defaultCatalog.trim().length() > 0)) {
   this.defaultCatalog = defaultCatalog;
  } else {
   this.defaultCatalog = null;
  }
  this.restartNeeded = true;
 }

 /**
  * The fully qualified Java class name of the JDBC driver to be used.
  */
 protected String driverClassName = null;

 @Override
 public synchronized String getDriverClassName() {
  return this.driverClassName;
 }

 @Override
 public synchronized void setDriverClassName(String driverClassName) {
  if ((driverClassName != null) && (driverClassName.trim().length() > 0)) {
   this.driverClassName = driverClassName;
  } else {
   this.driverClassName = null;
  }
  this.restartNeeded = true;
 }

 /**
  * The maximum number of active connections that can be allocated from this
  * pool at the same time, or zero for no limit.
  */
 protected int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;

 @Override
 public synchronized int getMaxActive() {
  return this.maxActive;
 }

 @Override
 public synchronized void setMaxActive(int maxActive) {
  this.maxActive = maxActive;
  if (connectionPool != null) {
   connectionPool.setMaxActive(maxActive);
  }
 }

 /**
  * The maximum number of active connections that can remain idle in the
  * pool, without extra ones being released, or zero for no limit.
  */
 protected int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;;

 @Override
 public synchronized int getMaxIdle() {
  return this.maxIdle;
 }

 @Override
 public synchronized void setMaxIdle(int maxIdle) {
  this.maxIdle = maxIdle;
  if (connectionPool != null) {
   connectionPool.setMaxIdle(maxIdle);
  }
 }

 /**
  * The minimum number of active connections that can remain idle in the
  * pool, without extra ones being created, or 0 to create none.
  */
 protected int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;;

 @Override
 public synchronized int getMinIdle() {
  return this.minIdle;
 }

 @Override
 public synchronized void setMinIdle(int minIdle) {
  this.minIdle = minIdle;
  if (connectionPool != null) {
   connectionPool.setMinIdle(minIdle);
  }
 }

 /**
  * The initial number of connections that are created when the pool is
  * started.
  *
  * @since 1.2
  */
 protected int initialSize = 0;

 @Override
 public synchronized int getInitialSize() {
  return this.initialSize;
 }

 @Override
 public synchronized void setInitialSize(int initialSize) {
  this.initialSize = initialSize;
  this.restartNeeded = true;
 }

 /**
  * The maximum number of milliseconds that the pool will wait (when there
  * are no available connections) for a connection to be returned before
  * throwing an exception, or -1 to wait indefinitely.
  */
 protected long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;

 @Override
 public synchronized long getMaxWait() {
  return this.maxWait;
 }

 @Override
 public synchronized void setMaxWait(long maxWait) {
  this.maxWait = maxWait;
  if (connectionPool != null) {
   connectionPool.setMaxWait(maxWait);
  }
 }

 /**
  * Prepared statement pooling for this pool.
  */
 protected boolean poolPreparedStatements = false;

 /**
  * Returns true if we are pooling statements.
  *
  * @return boolean
  */
 @Override
 public synchronized boolean isPoolPreparedStatements() {
  return this.poolPreparedStatements;
 }

 /**
  * Sets whether to pool statements or not.
  *
  * @param poolPreparedStatements pooling on or off
  */
 @Override
 public synchronized void setPoolPreparedStatements(boolean poolingStatements) {
  this.poolPreparedStatements = poolingStatements;
  this.restartNeeded = true;
 }

 /**
  * The maximum number of open statements that can be allocated from the
  * statement pool at the same time, or zero for no limit. Since a connection
  * usually only uses one or two statements at a time, this is mostly used to
  * help detect resource leaks.
  */
 protected int maxOpenPreparedStatements = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;

 @Override
 public synchronized int getMaxOpenPreparedStatements() {
  return this.maxOpenPreparedStatements;
 }

 @Override
 public synchronized void setMaxOpenPreparedStatements(int maxOpenStatements) {
  this.maxOpenPreparedStatements = maxOpenStatements;
  this.restartNeeded = true;
 }

 /**
  * The indication of whether objects will be validated before being borrowed
  * from the pool. If the object fails to validate, it will be dropped from
  * the pool, and we will attempt to borrow another.
  */
 protected boolean testOnBorrow = true;

 @Override
 public synchronized boolean getTestOnBorrow() {
  return this.testOnBorrow;
 }

 @Override
 public synchronized void setTestOnBorrow(boolean testOnBorrow) {
  this.testOnBorrow = testOnBorrow;
  if (connectionPool != null) {
   connectionPool.setTestOnBorrow(testOnBorrow);
  }
 }

 /**
  * The indication of whether objects will be validated before being returned
  * to the pool.
  */
 protected boolean testOnReturn = false;

 @Override
 public synchronized boolean getTestOnReturn() {
  return this.testOnReturn;
 }

 @Override
 public synchronized void setTestOnReturn(boolean testOnReturn) {
  this.testOnReturn = testOnReturn;
  if (connectionPool != null) {
   connectionPool.setTestOnReturn(testOnReturn);
  }
 }

 /**
  * The number of milliseconds to sleep between runs of the idle object
  * evictor thread. When non-positive, no idle object evictor thread will be
  * run.
  */
 protected long timeBetweenEvictionRunsMillis = GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;

 @Override
 public synchronized long getTimeBetweenEvictionRunsMillis() {
  return this.timeBetweenEvictionRunsMillis;
 }

 @Override
 public synchronized void setTimeBetweenEvictionRunsMillis(
   long timeBetweenEvictionRunsMillis) {
  this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
  if (connectionPool != null) {
   connectionPool
     .setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
  }
 }

 /**
  * The number of objects to examine during each run of the idle object
  * evictor thread (if any).
  */
 protected int numTestsPerEvictionRun = GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;

 @Override
 public synchronized int getNumTestsPerEvictionRun() {
  return this.numTestsPerEvictionRun;
 }

 @Override
 public synchronized void setNumTestsPerEvictionRun(
   int numTestsPerEvictionRun) {
  this.numTestsPerEvictionRun = numTestsPerEvictionRun;
  if (connectionPool != null) {
   connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
  }
 }

 /**
  * The minimum amount of time an object may sit idle in the pool before it
  * is eligable for eviction by the idle object evictor (if any).
  */
 protected long minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;

 @Override
 public synchronized long getMinEvictableIdleTimeMillis() {
  return this.minEvictableIdleTimeMillis;
 }

 @Override
 public synchronized void setMinEvictableIdleTimeMillis(
   long minEvictableIdleTimeMillis) {
  this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
  if (connectionPool != null) {
   connectionPool
     .setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
  }
 }

 /**
  * The indication of whether objects will be validated by the idle object
  * evictor (if any). If an object fails to validate, it will be dropped from
  * the pool.
  */
 protected boolean testWhileIdle = false;

 @Override
 public synchronized boolean getTestWhileIdle() {
  return this.testWhileIdle;
 }

 @Override
 public synchronized void setTestWhileIdle(boolean testWhileIdle) {
  this.testWhileIdle = testWhileIdle;
  if (connectionPool != null) {
   connectionPool.setTestWhileIdle(testWhileIdle);
  }
 }

 /**
  * [Read Only] The current number of active connections that have been
  * allocated from this data source.
  */
 @Override
 public synchronized int getNumActive() {
  if (connectionPool != null) {
   return connectionPool.getNumActive();
  } else {
   return 0;
  }
 }

 /**
  * [Read Only] The current number of idle connections that are waiting to be
  * allocated from this data source.
  */
 @Override
 public synchronized int getNumIdle() {
  if (connectionPool != null) {
   return connectionPool.getNumIdle();
  } else {
   return 0;
  }
 }

 /**
  * The connection password to be passed to our JDBC driver to establish a
  * connection.
  */
 protected String password = null;

 @Override
 public synchronized String getPassword() {
  return this.password;
 }

 @Override
 public synchronized void setPassword(String password) {
  this.password = password;
  this.restartNeeded = true;
 }

 /**
  * The connection URL to be passed to our JDBC driver to establish a
  * connection.
  */
 protected String url = null;

 @Override
 public synchronized String getUrl() {
  return this.url;
 }

 @Override
 public synchronized void setUrl(String url) {
  this.url = url;
  this.restartNeeded = true;
 }

 /**
  * The connection username to be passed to our JDBC driver to establish a
  * connection.
  */
 protected String username = null;

 @Override
 public synchronized String getUsername() {
  return this.username;
 }

 @Override
 public synchronized void setUsername(String username) {
  this.username = username;
  this.restartNeeded = true;
 }

 /**
  * The SQL query that will be used to validate connections from this pool
  * before returning them to the caller. If specified, this query
  * <strong>MUST</strong> be an SQL SELECT statement that returns at least
  * one row.
  */
 protected String validationQuery = null;

 @Override
 public synchronized String getValidationQuery() {
  return this.validationQuery;
 }

 @Override
 public synchronized void setValidationQuery(String validationQuery) {
  if ((validationQuery != null) && (validationQuery.trim().length() > 0)) {
   this.validationQuery = validationQuery;
  } else {
   this.validationQuery = null;
  }
  this.restartNeeded = true;
 }

 /**
  * Controls access to the underlying connection
  */
 private boolean accessToUnderlyingConnectionAllowed = false;

 /**
  * Returns the value of the accessToUnderlyingConnectionAllowed property.
  *
  * @return true if access to the underlying is allowed, false otherwise.
  */
 @Override
 public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
  return this.accessToUnderlyingConnectionAllowed;
 }

 /**
  * Sets the value of the accessToUnderlyingConnectionAllowed property. It
  * controls if the PoolGuard allows access to the underlying connection.
  * (Default: false)
  *
  * @param allow Access to the underlying connection is granted when true.
  */
 @Override
 public synchronized void setAccessToUnderlyingConnectionAllowed(
   boolean allow) {
  this.accessToUnderlyingConnectionAllowed = allow;
  this.restartNeeded = true;
 }

 // ----------------------------------------------------- Instance Variables

 // TODO: review & make isRestartNeeded() public, restartNeeded protected

 private boolean restartNeeded = false;

 /**
  * Returns whether or not a restart is needed.
  *
  * @return true if a restart is needed
  */
 private synchronized boolean isRestartNeeded() {
  return restartNeeded;
 }

 /**
  * The object pool that internally manages our connections.
  */
 protected GenericObjectPool connectionPool = null;

 /**
  * The connection properties that will be sent to our JDBC driver when
  * establishing new connections. <strong>NOTE</strong> - The "user" and
  * "password" properties will be passed explicitly, so they do not need to
  * be included here.
  */
 protected Properties connectionProperties = new Properties();

 /**
  * The data source we will use to manage connections. This object should be
  * acquired <strong>ONLY</strong> by calls to the
  * <code>createDataSource()</code> method.
  */
 protected DataSource dataSource = null;

 /**
  * The PrintWriter to which log messages should be directed.
  */
 protected PrintWriter logWriter = new PrintWriter(System.out);

 // ----------------------------------------------------- DataSource Methods

 /**
  * Create (if necessary) and return a connection to the database.
  *
  * @exception SQLException if a database access error occurs
  */
 @Override
 public Connection getConnection() throws SQLException {
  return createDataSource().getConnection();
 }

 /**
  * Create (if necessary) and return a connection to the database.
  *
  * @param username Database user on whose behalf the Connection is being
  *            made
  * @param password The database user's password
  *
  * @exception SQLException if a database access error occurs
  */
 @Override
 public Connection getConnection(String username, String password)
   throws SQLException {
  return createDataSource().getConnection(username, password);
 }

 /**
  * Return the login timeout (in seconds) for connecting to the database.
  *
  * @exception SQLException if a database access error occurs
  */
 @Override
 public int getLoginTimeout() throws SQLException {
  return createDataSource().getLoginTimeout();
 }

 /**
  * Return the log writer being used by this data source.
  *
  * @exception SQLException if a database access error occurs
  */
 @Override
 public PrintWriter getLogWriter() throws SQLException {
  return createDataSource().getLogWriter();
 }

 /**
  * Set the login timeout (in seconds) for connecting to the database.
  *
  * @param loginTimeout The new login timeout, or zero for no timeout
  *
  * @exception SQLException if a database access error occurs
  */
 @Override
 public void setLoginTimeout(int loginTimeout) throws SQLException {
  createDataSource().setLoginTimeout(loginTimeout);
 }

 /**
  * Set the log writer being used by this data source.
  *
  * @param logWriter The new log writer
  *
  * @exception SQLException if a database access error occurs
  */
 @Override
 public void setLogWriter(PrintWriter logWriter) throws SQLException {
  createDataSource().setLogWriter(logWriter);
  this.logWriter = logWriter;
 }

 private AbandonedConfig abandonedConfig;

 /**
  * Flag to remove abandoned connections if they exceed the
  * removeAbandonedTimout.
  *
  * Set to true or false, default false. If set to true a connection is
  * considered abandoned and eligible for removal if it has been idle longer
  * than the removeAbandonedTimeout. Setting this to true can recover db
  * connections from poorly written applications which fail to close a
  * connection.
  *
  * @deprecated
  */
 @Override
 public boolean getRemoveAbandoned() {
  if (abandonedConfig != null) {
   return abandonedConfig.getRemoveAbandoned();
  }
  return false;
 }

 /**
  * @deprecated
  * @param removeAbandoned
  */
 public void setRemoveAbandoned(boolean removeAbandoned) {
  if (abandonedConfig == null) {
   abandonedConfig = new AbandonedConfig();
  }
  abandonedConfig.setRemoveAbandoned(removeAbandoned);
  this.restartNeeded = true;
 }

 /**
  * Timeout in seconds before an abandoned connection can be removed.
  *
  * Defaults to 300 seconds.
  *
  * @deprecated
  */
 public int getRemoveAbandonedTimeout() {
  if (abandonedConfig != null) {
   return abandonedConfig.getRemoveAbandonedTimeout();
  }
  return 300;
 }

 /**
  * @deprecated
  * @param removeAbandonedTimeout
  */
 public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
  if (abandonedConfig == null) {
   abandonedConfig = new AbandonedConfig();
  }
  abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
  this.restartNeeded = true;
 }

 /**
  * Flag to log stack traces for application code which abandoned a Statement
  * or Connection.
  *
  * Defaults to false.
  *
  * Logging of abandoned Statements and Connections adds overhead for every
  * Connection open or new Statement because a stack trace has to be
  * generated.
  *
  * @deprecated
  */
 public boolean getLogAbandoned() {
  if (abandonedConfig != null) {
   return abandonedConfig.getLogAbandoned();
  }
  return false;
 }

 /**
  * @deprecated
  * @param logAbandoned
  */
 public void setLogAbandoned(boolean logAbandoned) {
  if (abandonedConfig == null) {
   abandonedConfig = new AbandonedConfig();
  }
  abandonedConfig.setLogAbandoned(logAbandoned);
  this.restartNeeded = true;
 }

 // --------------------------------------------------------- Public Methods

 /**
  * Add a custom connection property to the set that will be passed to our
  * JDBC driver. This <strong>MUST</strong> be called before the first
  * connection is retrieved (along with all the other configuration property
  * setters).
  *
  * @param name Name of the custom connection property
  * @param value Value of the custom connection property
  */
 @Override
 public void addConnectionProperty(String name, String value) {
  connectionProperties.put(name, value);
  this.restartNeeded = true;
 }

 @Override
 public void removeConnectionProperty(String name) {
  connectionProperties.remove(name);
  this.restartNeeded = true;
 }

 /**
  * Close and release all connections that are currently stored in the
  * connection pool associated with our data source.
  *
  * @exception SQLException if a database error occurs
  */
 @Override
 public synchronized void close() throws SQLException {
  GenericObjectPool oldpool = connectionPool;
  connectionPool = null;
  dataSource = null;
  try {
   if (oldpool != null) {
    oldpool.close();
   }
  } catch (SQLException e) {
   throw e;
  } catch (RuntimeException e) {
   throw e;
  } catch (Exception e) {
   throw new SQLNestedException("Cannot close connection pool", e);
  }
 }

 // ------------------------------------------------------ Protected Methods

 /**
  * <p>
  * Create (if necessary) and return the internal data source we are using to
  * manage our connections.
  * </p>
  *
  * <p>
  * <strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the "double
  * checked locking" idiom in an attempt to avoid synchronizing on every
  * single call to this method. However, this idiom fails to work correctly
  * in the face of some optimizations that are legal for a JVM to perform.
  * </p>
  *
  * @exception SQLException if the object pool cannot be created.
  */
 @Override
 protected synchronized DataSource createDataSource() throws SQLException {

  // Return the pool if we have already created it
  if (dataSource != null) {
   return (dataSource);
  }

  // Load the JDBC driver class
  if (driverClassName != null) {
   try {
    Class.forName(driverClassName);
   } catch (Throwable t) {
    String message = "Cannot load JDBC driver class '"
      + driverClassName + "'";
    logWriter.println(message);
    t.printStackTrace(logWriter);
    throw new SQLNestedException(message, t);
   }
  }

  // Create a JDBC driver instance
  Driver driver = null;
  try {
   driver = DriverManager.getDriver(url);
  } catch (Throwable t) {
   String message = "Cannot create JDBC driver of class '"
     + (driverClassName != null ? driverClassName : "")
     + "' for connect URL '" + url + "'";
   logWriter.println(message);
   t.printStackTrace(logWriter);
   throw new SQLNestedException(message, t);
  }

  // Can't test without a validationQuery
  if (validationQuery == null) {
   setTestOnBorrow(false);
   setTestOnReturn(false);
   setTestWhileIdle(false);
  }

  // Create an object pool to contain our active connections
  if ((abandonedConfig != null)
    && (abandonedConfig.getRemoveAbandoned() == true)) {
   connectionPool = new AbandonedObjectPool(null, abandonedConfig);
  } else {
   connectionPool = new GenericObjectPool();
  }
  connectionPool.setMaxActive(maxActive);
  connectionPool.setMaxIdle(maxIdle);
  connectionPool.setMinIdle(minIdle);
  connectionPool.setMaxWait(maxWait);
  connectionPool.setTestOnBorrow(testOnBorrow);
  connectionPool.setTestOnReturn(testOnReturn);
  connectionPool
    .setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
  connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
  connectionPool
    .setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
  connectionPool.setTestWhileIdle(testWhileIdle);

  // Set up statement pool, if desired
  GenericKeyedObjectPoolFactory statementPoolFactory = null;
  if (isPoolPreparedStatements()) {
   statementPoolFactory = new GenericKeyedObjectPoolFactory(null, -1, // unlimited
     // maxActive
     // (per
     // key)
     GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL, 0, // maxWait
     1, // maxIdle (per key)
     maxOpenPreparedStatements);
  }

  // Set up the driver connection factory we will use
  if (username != null) {
   connectionProperties.put("user", username);
  } else {
   log("DBCP DataSource configured without a 'username'");
  }

  if (password != null) {
   connectionProperties.put("password", password);
  } else {
   log("DBCP DataSource configured without a 'password'");
  }

  DriverConnectionFactory driverConnectionFactory = new DriverConnectionFactoryExtendListeerImpl(
    listeners, driver, url, connectionProperties);

  // Set up the poolable connection factory we will use
  PoolableConnectionFactory connectionFactory = null;
  try {
   connectionFactory = new PoolableConnectionFactory(
     driverConnectionFactory, connectionPool,
     statementPoolFactory, validationQuery, defaultReadOnly,
     defaultAutoCommit, defaultTransactionIsolation,
     defaultCatalog, abandonedConfig);
   if (connectionFactory == null) {
    throw new SQLException(
      "Cannot create PoolableConnectionFactory");
   }
   validateConnectionFactory(connectionFactory);
  } catch (RuntimeException e) {
   throw e;
  } catch (Exception e) {
   throw new SQLNestedException(
     "Cannot create PoolableConnectionFactory ("
       + e.getMessage() + ")", e);
  }

  // Create and return the pooling data source to manage the connections
  dataSource = new PoolingDataSource(connectionPool);
  ((PoolingDataSource) dataSource)
    .setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
  dataSource.setLogWriter(logWriter);

  try {
   for (int i = 0; i < initialSize; i++) {
    connectionPool.addObject();
   }
  } catch (Exception e) {
   throw new SQLNestedException(
     "Error preloading the connection pool", e);
  }

  return dataSource;
 }

 private static void validateConnectionFactory(
   PoolableConnectionFactory connectionFactory) throws Exception {
  Connection conn = null;
  try {
   conn = (Connection) connectionFactory.makeObject();
   connectionFactory.activateObject(conn);
   connectionFactory.validateConnection(conn);
   connectionFactory.passivateObject(conn);
  } finally {
   connectionFactory.destroyObject(conn);
  }
 }

 private void restart() {
  try {
   close();
  } catch (SQLException e) {
   log("Could not restart DataSource, cause: " + e.getMessage());
  }
 }

 private void log(String message) {
  if (logWriter != null) {
   logWriter.println(message);
  }
 }
}

public class DriverConnectionFactoryExtendListeerImpl extends
  DriverConnectionFactory {
 private List<ListenerConfig> listeners;

 public DriverConnectionFactoryTempTableImpl(List<ListenerConfig> listeners,
   Driver driver, String connectUri, Properties props) {
  super(driver, connectUri, props);
  this.listeners = listeners;
 }

 @Override
 public Connection createConnection() throws SQLException {
  Connection connect = _driver.connect(_connectUri, _props);
  System.out.println("获取数据库连接");
  for (ListenerConfig config : listeners) {
   try {
    IConnectionListener listenerImpl = (IConnectionListener) Class
      .forName(config.getClassName()).newInstance();
    listenerImpl.createConnection(connect, config);
   } catch (Throwable e) {
    return null;
   }
  }
  return connect;
 }
}

public interface IConnectionListener {
 void createConnection(Connection con, ListenerConfig config)
   throws SQLException;
}

public class ListenerConfig {
 private Map<String, String> attributes = new HashMap<String, String>();

 private String className;

 @SuppressWarnings("unchecked")
 public ListenerConfig(Element listenerElement) {
  className = listenerElement.elementText("class");
  Iterator attributeElements = listenerElement
    .elementIterator("attribute");
  while (attributeElements.hasNext()) {
   Element attributeElement = (Element) attributeElements.next();
   attributes.put(attributeElement.elementText("name"),
     attributeElement.elementText("value"));
  }
 }

 public void setAttribute(String name, String value) {
  attributes.put(name, value);
 }

 public String getAttribute(String name) {
  return attributes.get(name);
 }

 public Set<String> getAttributeNames() {
  return attributes.keySet();
 }

 public String getClassName() {
  return className;
 }


使用的时候根据实际情况将Listener传进BasicDataSourceExtendListenerImpl,或者在初始化BasicDataSourceExtendListenerImpl时直接读取。

原创粉丝点击