mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
318 lines
11 KiB
Java
318 lines
11 KiB
Java
/*
|
|
* Copyright 1999-2011 Alibaba Group Holding Ltd.
|
|
*
|
|
* 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.proxy;
|
|
|
|
import java.lang.management.ManagementFactory;
|
|
import java.sql.Connection;
|
|
import java.sql.Driver;
|
|
import java.sql.DriverManager;
|
|
import java.sql.DriverPropertyInfo;
|
|
import java.sql.SQLException;
|
|
import java.sql.SQLFeatureNotSupportedException;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Properties;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ConcurrentMap;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.management.MBeanServer;
|
|
import javax.management.ObjectName;
|
|
|
|
import com.alibaba.druid.VERSION;
|
|
import com.alibaba.druid.filter.Filter;
|
|
import com.alibaba.druid.proxy.config.AbstractDruidFilterConfig;
|
|
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
|
|
import com.alibaba.druid.proxy.jdbc.DataSourceProxyConfig;
|
|
import com.alibaba.druid.proxy.jdbc.DataSourceProxyImpl;
|
|
import com.alibaba.druid.stat.JdbcStatManager;
|
|
import com.alibaba.druid.support.logging.Log;
|
|
import com.alibaba.druid.support.logging.LogFactory;
|
|
import com.alibaba.druid.util.DruidLoaderUtils;
|
|
import com.alibaba.druid.util.JMXUtils;
|
|
import com.alibaba.druid.util.JdbcUtils;
|
|
|
|
/**
|
|
* @author wenshao<szujobs@hotmail.com>
|
|
*/
|
|
public class DruidDriver implements Driver, DruidDriverMBean {
|
|
|
|
private final static Log LOG = LogFactory.getLog(DruidDriver.class);
|
|
|
|
private final static DruidDriver instance = new DruidDriver();
|
|
|
|
private final static ConcurrentMap<String, DataSourceProxyImpl> proxyDataSources = new ConcurrentHashMap<String, DataSourceProxyImpl>();
|
|
private final static AtomicInteger dataSourceIdSeed = new AtomicInteger(0);
|
|
|
|
public final static String DEFAULT_PREFIX = "jdbc:wrap-jdbc:";
|
|
public final static String DRIVER_PREFIX = "driver=";
|
|
public final static String PASSWORD_CALLBACK_PREFIX = "passwordCallback=";
|
|
public final static String NAME_PREFIX = "name=";
|
|
public final static String JMX_PREFIX = "jmx=";
|
|
public final static String FILTERS_PREFIX = "filters=";
|
|
|
|
private final AtomicLong connectCount = new AtomicLong(0);
|
|
|
|
private String acceptPrefix = DEFAULT_PREFIX;
|
|
|
|
private int majorVersion = 4;
|
|
|
|
private int minorVersion = 0;
|
|
|
|
private final static String MBEAN_NAME = "com.alibaba.druid:type=DruidDriver";
|
|
|
|
static {
|
|
registerDriver(instance);
|
|
}
|
|
|
|
public static boolean registerDriver(Driver driver) {
|
|
try {
|
|
DriverManager.registerDriver(driver);
|
|
|
|
try {
|
|
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
|
|
|
|
ObjectName objectName = new ObjectName(MBEAN_NAME);
|
|
if (!mbeanServer.isRegistered(objectName)) {
|
|
mbeanServer.registerMBean(instance, objectName);
|
|
}
|
|
} catch (Exception ex) {
|
|
LOG.error("register druid-driver mbean error", ex);
|
|
}
|
|
|
|
return true;
|
|
} catch (Exception e) {
|
|
LOG.error("registerDriver error", e);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public DruidDriver(){
|
|
|
|
}
|
|
|
|
public static DruidDriver getInstance() {
|
|
return instance;
|
|
}
|
|
|
|
public static int createDataSourceId() {
|
|
return dataSourceIdSeed.incrementAndGet();
|
|
}
|
|
|
|
@Override
|
|
public boolean acceptsURL(String url) throws SQLException {
|
|
if (url == null) {
|
|
return false;
|
|
}
|
|
|
|
if (url.startsWith(acceptPrefix)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public Connection connect(String url, Properties info) throws SQLException {
|
|
if (!acceptsURL(url)) {
|
|
return null;
|
|
}
|
|
|
|
connectCount.incrementAndGet();
|
|
|
|
DataSourceProxyImpl dataSource = getDataSource(url, info);
|
|
|
|
return dataSource.connect(info);
|
|
}
|
|
|
|
/**
|
|
* 参数定义: com.alibaba.druid.log.LogFilter=filter com.alibaba.druid.log.LogFilter.p1=prop-value
|
|
* com.alibaba.druid.log.LogFilter.p2=prop-value
|
|
*
|
|
* @param url
|
|
* @return
|
|
* @throws SQLException
|
|
*/
|
|
private DataSourceProxyImpl getDataSource(String url, Properties info) throws SQLException {
|
|
DataSourceProxyImpl dataSource = proxyDataSources.get(url);
|
|
|
|
if (dataSource == null) {
|
|
DataSourceProxyConfig config = parseConfig(url, info);
|
|
|
|
Driver rawDriver = createDriver(config.getRawDriverClassName());
|
|
|
|
DataSourceProxyImpl newDataSource = new DataSourceProxyImpl(rawDriver, config);
|
|
|
|
{
|
|
String property = System.getProperty("druid.filters");
|
|
if (property != null && property.length() > 0) {
|
|
for (String filterItem : property.split(",")) {
|
|
DruidLoaderUtils.loadFilter(config.getFilters(), filterItem);
|
|
}
|
|
}
|
|
}
|
|
{
|
|
int dataSourceId = createDataSourceId();
|
|
newDataSource.setId(dataSourceId);
|
|
|
|
for (Filter filter : config.getFilters()) {
|
|
filter.init(newDataSource);
|
|
}
|
|
}
|
|
|
|
DataSourceProxy oldDataSource = proxyDataSources.putIfAbsent(url, newDataSource);
|
|
if (oldDataSource == null) {
|
|
if (config.isJmxOption()) {
|
|
JMXUtils.register("com.alibaba.druid:type=JdbcStat", JdbcStatManager.getInstance());
|
|
}
|
|
}
|
|
|
|
dataSource = proxyDataSources.get(url);
|
|
}
|
|
return dataSource;
|
|
}
|
|
|
|
public static DataSourceProxyConfig parseConfig(String url, Properties info) throws SQLException {
|
|
String restUrl = url.substring(DEFAULT_PREFIX.length());
|
|
|
|
DataSourceProxyConfig config = new DataSourceProxyConfig();
|
|
|
|
List<AbstractDruidFilterConfig> druidFilterConfigList = new ArrayList<AbstractDruidFilterConfig>();
|
|
|
|
if (restUrl.startsWith(DRIVER_PREFIX)) {
|
|
int pos = restUrl.indexOf(':', DRIVER_PREFIX.length());
|
|
String driverText = restUrl.substring(DRIVER_PREFIX.length(), pos);
|
|
if (driverText.length() > 0) {
|
|
config.setRawDriverClassName(driverText.trim());
|
|
}
|
|
restUrl = restUrl.substring(pos + 1);
|
|
}
|
|
|
|
if (restUrl.startsWith(FILTERS_PREFIX)) {
|
|
int pos = restUrl.indexOf(':', FILTERS_PREFIX.length());
|
|
String filtersText = restUrl.substring(FILTERS_PREFIX.length(), pos);
|
|
for (String filterItem : filtersText.split(",")) {
|
|
DruidLoaderUtils.loadFilter(config.getFilters(), filterItem);
|
|
}
|
|
restUrl = restUrl.substring(pos + 1);
|
|
}
|
|
// 如果url中并无定义filter 采用配置
|
|
if (config.getFilters().size() <= 0) {
|
|
DruidLoaderUtils.loadFilter(config.getFilters(), druidFilterConfigList);
|
|
}
|
|
|
|
if (restUrl.startsWith(NAME_PREFIX)) {
|
|
int pos = restUrl.indexOf(':', NAME_PREFIX.length());
|
|
String name = restUrl.substring(NAME_PREFIX.length(), pos);
|
|
config.setName(name);
|
|
restUrl = restUrl.substring(pos + 1);
|
|
}
|
|
|
|
if (restUrl.startsWith(JMX_PREFIX)) {
|
|
int pos = restUrl.indexOf(':', JMX_PREFIX.length());
|
|
String jmxOption = restUrl.substring(JMX_PREFIX.length(), pos);
|
|
config.setJmxOption(jmxOption);
|
|
restUrl = restUrl.substring(pos + 1);
|
|
}
|
|
|
|
String rawUrl = restUrl;
|
|
config.setRawUrl(rawUrl);
|
|
|
|
if (config.getRawDriverClassName() == null) {
|
|
String rawDriverClassname = JdbcUtils.getDriverClassName(rawUrl);
|
|
config.setRawDriverClassName(rawDriverClassname);
|
|
}
|
|
|
|
config.setUrl(url);
|
|
return config;
|
|
}
|
|
|
|
public Driver createDriver(String className) throws SQLException {
|
|
Class<?> rawDriverClass = DruidLoaderUtils.loadClass(className);
|
|
|
|
if (rawDriverClass == null) {
|
|
throw new SQLException("jdbc-driver's class not found. '" + className + "'");
|
|
}
|
|
|
|
Driver rawDriver;
|
|
try {
|
|
rawDriver = (Driver) rawDriverClass.newInstance();
|
|
} catch (InstantiationException e) {
|
|
throw new SQLException("create driver instance error, driver className '" + className + "'");
|
|
} catch (IllegalAccessException e) {
|
|
throw new SQLException("create driver instance error, driver className '" + className + "'");
|
|
}
|
|
|
|
return rawDriver;
|
|
}
|
|
|
|
@Override
|
|
public int getMajorVersion() {
|
|
return this.majorVersion;
|
|
}
|
|
|
|
@Override
|
|
public int getMinorVersion() {
|
|
return this.minorVersion;
|
|
}
|
|
|
|
@Override
|
|
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
|
|
DataSourceProxyImpl dataSource = getDataSource(url, info);
|
|
return dataSource.getRawDriver().getPropertyInfo(dataSource.getConfig().getRawUrl(), info);
|
|
}
|
|
|
|
@Override
|
|
public boolean jdbcCompliant() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public long getConnectCount() {
|
|
return connectCount.get();
|
|
}
|
|
|
|
public String getAcceptPrefix() {
|
|
return acceptPrefix;
|
|
}
|
|
|
|
@Override
|
|
public String[] getDataSourceUrls() {
|
|
return proxyDataSources.keySet().toArray(new String[proxyDataSources.size()]);
|
|
}
|
|
|
|
public static ConcurrentMap<String, DataSourceProxyImpl> getProxyDataSources() {
|
|
return proxyDataSources;
|
|
}
|
|
|
|
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
|
throw new SQLFeatureNotSupportedException();
|
|
}
|
|
|
|
@Override
|
|
public void resetStat() {
|
|
connectCount.set(0);
|
|
}
|
|
|
|
@Override
|
|
public String getDruidVersion() {
|
|
return VERSION.getVersionNumber();
|
|
}
|
|
}
|