refactor ConfigFilter, remove ConfigLoader

This commit is contained in:
wenshao
2012-08-31 22:09:25 +08:00
parent b2e42115df
commit f9279bac88
9 changed files with 94 additions and 504 deletions
@@ -15,27 +15,30 @@
*/
package com.alibaba.druid.filter.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.sql.SQLException;
import java.util.Properties;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.config.loader.ConfigLoader;
import com.alibaba.druid.filter.config.loader.ConfigLoaderFactory;
import com.alibaba.druid.filter.config.security.decrypter.DecryptException;
import com.alibaba.druid.filter.config.security.decrypter.Decrypter;
import com.alibaba.druid.filter.config.security.decrypter.DecrypterFactory;
import com.alibaba.druid.filter.config.security.decrypter.SensitiveParameters;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.filter.config.security.decrypter.DecryptException;
import com.alibaba.druid.filter.config.security.decrypter.Decrypter;
import com.alibaba.druid.filter.config.security.decrypter.DecrypterFactory;
import com.alibaba.druid.filter.config.security.decrypter.SensitiveParameters;
import java.sql.SQLException;
import java.util.Properties;
import com.alibaba.druid.util.JdbcUtils;
/**
* <pre>
* 这个类主要是负责两个事情, 解密, 和下载远程的配置文件
* [解密]
*
*
* DruidDataSource dataSource = new DruidDataSource();
* //dataSource.setXXX 其他设置
* //下面两步很重要
@@ -44,7 +47,7 @@ import java.util.Properties;
* //使用RSA解密(使用默认密钥)
* dataSource.setConnectionPropertise("config.decrypt=RSA");
* dataSource.setPassword("加密的密文");
*
*
* [远程配置文件]
* DruidDataSource dataSource = new DruidDataSource();
* //下面两步很重要
@@ -52,49 +55,49 @@ import java.util.Properties;
* dataSource.setFilters("config");
* //使用RSA解密(使用默认密钥)
* dataSource.setConnectionPropertise("config.file=http://localhost:8080/remote.propreties;");
*
*
* [Spring的配置解密]
*
*
* &lt;bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"&gt;
* &lt;property name="password" value="加密的密文" /&gt;
* &lt;!-- 其他的属性设置 --&gt;
* &lt;property name="filters" value="config" /&gt;
* &lt;property name="connectionProperties" value="config.decrypt=RSA" /&gt;
* &lt;/bean&gt;
*
*
* [Spring的配置远程配置文件]
*
*
* &lt;bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"&gt;
* &lt;property name="filters" value="config" /&gt;
* &lt;property name="connectionProperties" value="config.file=http://localhost:8080/remote.propreties; /&gt;
* &lt;/bean&gt;
*
*
* [使用系统属性配置远程文件]
* java -Ddruid.config.file=file:/home/test/my.properties ...
*
*
* 远程配置文件格式:
* 1. 其他的属性KEY请查看 @see com.alibaba.druid.pool.DruidDataSourceFactory
* 2. config filter 相关设置:
* #远程文件路径
* config.file=http://xxxxx(http://开头或者file:开头)
*
*
* #RSA解密, Key不指定, 使用默认的
* config.decrypt=RSA
* config.decrypt.key=密钥字符串
* config.decrypt.keyFile=密钥文件路径
* config.decrypt.x509File=证书路径
*
*
* </pre>
*/
public class ConfigFilter extends FilterAdapter {
private static Log log = LogFactory.getLog(ConfigFilter.class);
private static Log log = LogFactory.getLog(ConfigFilter.class);
public static final String CONFIG_FILE = "config.file";
public static final String CONFIG_FILE = "config.file";
public static final String CONFIG_DECRYPT = "config.decrypt";
public static final String CONFIG_DECRYPT = "config.decrypt";
public static final String SYS_PROP_CONFIG_FILE = "druid.config.file";
public static final String SYS_PROP_CONFIG_FILE = "druid.config.file";
public ConfigFilter(){
}
@@ -108,30 +111,24 @@ public class ConfigFilter extends FilterAdapter {
DruidDataSource dataSource = (DruidDataSource) dataSourceProxy;
Properties connectinProperties = dataSource.getConnectProperties();
//获取远程配置文件
String protocol = connectinProperties.getProperty(CONFIG_FILE);
// 获取远程配置文件
String configFile = connectinProperties.getProperty(CONFIG_FILE);
//如果系统参数有指定
if (protocol == null) {
protocol = System.getProperty(SYS_PROP_CONFIG_FILE);
// 如果系统参数有指定
if (configFile == null) {
configFile = System.getProperty(SYS_PROP_CONFIG_FILE);
}
if (protocol != null && protocol.length() > 0) {
if (configFile != null && configFile.length() > 0) {
if (log.isDebugEnabled()) {
log.debug("Config file will be load from [" + protocol + "].");
log.debug("Config file will be load from [" + configFile + "].");
}
//获取配置文件内容
ConfigLoader configLoader = ConfigLoaderFactory.getConfigLoader(protocol);
if (configLoader == null) {
throw new IllegalArgumentException("Druid doesn't support the [config.file=" + protocol + "] to load remote config file.");
}
info = configLoader.loadConfig(protocol);
info = loadConfig(configFile);
if (info == null) {
throw new IllegalArgumentException("Cannot load remote config file from the [config.file=" + protocol + "].");
throw new IllegalArgumentException("Cannot load remote config file from the [config.file=" + configFile
+ "].");
}
} else {
info = new Properties();
@@ -140,7 +137,7 @@ public class ConfigFilter extends FilterAdapter {
}
}
//判断是否需要解密,如果需要就进行解密行动
// 判断是否需要解密,如果需要就进行解密行动
String decrypterId = info.getProperty(CONFIG_DECRYPT);
boolean isRemotedSecurityConfig = true;
@@ -165,12 +162,11 @@ public class ConfigFilter extends FilterAdapter {
try {
Decrypter decrypter = DecrypterFactory.getDecrypter(decrypterId);
if (decrypter == null) {
throw new IllegalArgumentException("Druid doesn't support the decrypter [config.decrypt=" + decrypterId + "].");
throw new IllegalArgumentException("Druid doesn't support the decrypter [config.decrypt="
+ decrypterId + "].");
}
Properties securityInfo = isRemotedSecurityConfig
? info
: connectinProperties;
Properties securityInfo = isRemotedSecurityConfig ? info : connectinProperties;
SensitiveParameters originalParameter = getSensitiveParameters(dataSource, info);
SensitiveParameters parameters = decrypter.decrypt(originalParameter, securityInfo);
@@ -188,7 +184,7 @@ public class ConfigFilter extends FilterAdapter {
}
}
//没有任何配置
// 没有任何配置
if (info.size() == 0) {
if (log.isDebugEnabled()) {
log.debug("No config.");
@@ -205,6 +201,7 @@ public class ConfigFilter extends FilterAdapter {
/**
* 如果配置文件中没有值, 就取默认值
*
* @param dataSource
* @param info
* @return
@@ -228,16 +225,46 @@ public class ConfigFilter extends FilterAdapter {
return new SensitiveParameters(url, username, password);
}
public Properties loadConfig(String filePath) {
Properties properties = new Properties();
public int hashCode() {
return this.getClass().hashCode();
}
InputStream inStream = null;
try {
boolean xml = false;
if (filePath.startsWith("http://") || filePath.startsWith("https://") || filePath.startsWith("file:/")) {
URL url = new URL(filePath);
inStream = url.openStream();
public boolean equals(Object obj) {
if (obj == null) {
return false;
xml = url.getPath().endsWith(".xml");
} else {
File file = new File(filePath);
if (file.exists()) {
inStream = new FileInputStream(file);
} else {
inStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
}
xml = filePath.endsWith(".xml");
}
if (inStream == null) {
log.error("load config file error, file : " + filePath);
return null;
}
if (xml) {
properties.loadFromXML(inStream);
} else {
properties.load(inStream);
}
return properties;
} catch (Exception ex) {
log.error("load config file error, file : " + filePath, ex);
return null;
} finally {
JdbcUtils.close(inStream);
}
return obj.getClass().equals(ConfigFilter.class);
}
}
@@ -1,51 +0,0 @@
/*
* 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.filter.config.loader;
import java.util.Properties;
/**
* <pre>
* 配置文件装载器.
* </pre>
*
* @see com.alibaba.druid.filter.config.ConfigFilter
* @see ConfigLoaderFactory
*
* @author Jonas Yang
*/
public interface ConfigLoader {
/**
* 唯一的ID
* @return
*/
public String getId();
/**
* 获得配置内容, 如果没有, 返回<code>null</code>.
* @param protocol
* @return
*/
public Properties loadConfig(String protocol);
/**
* 是否支持该协议, 如果支持, 将会使用该装载器获取配置文件
* @param protocol
* @return
*/
public boolean isSupported(String protocol);
}
@@ -1,117 +0,0 @@
/*
* 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.filter.config.loader;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
import java.io.InputStream;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
/**
* <pre>
* 如果有扩展的装载器.
* 可以放到classes目录下的druid-config-loader.properties
*
* druid-config-loader.properties 内容如下:
* ConfigLoader.x=com.xx.xxx.xx.MyConfigLoader
*
* </pre>
* @author Jonas Yang
*/
public class ConfigLoaderFactory {
private static Log log = LogFactory.getLog(ConfigLoaderFactory.class);
private static ConcurrentHashMap<String, ConfigLoader> configLoaders = new ConcurrentHashMap<String, ConfigLoader>();
static {
//加载默认的装载器
initConfigLoader("META-INF/druid-config-loader-default.properties", ConfigLoaderFactory.class.getClassLoader());
//加载扩展的装载器
initConfigLoader("druid-config-loader.properties", ClassLoader.getSystemClassLoader());
if (ClassLoader.getSystemClassLoader() != Thread.currentThread().getContextClassLoader()) {
initConfigLoader("ConfigLoader.properties", Thread.currentThread().getContextClassLoader());
}
}
private ConfigLoaderFactory() {}
static void initConfigLoader(String resource, ClassLoader classLoader) {
if (resource == null) {
return;
}
InputStream inStream = null;
try {
inStream = classLoader.getResourceAsStream(resource);
if (inStream == null) {
return;
}
Properties p = new Properties();
p.load(inStream);
for (String key : p.stringPropertyNames()) {
String clazzName = p.getProperty(key);
System.out.println(clazzName);
Class<?> clazz = classLoader.loadClass(clazzName);
ConfigLoader configLoader = (ConfigLoader) clazz.newInstance();
addConfigLoader(configLoader);
}
} catch (Exception e) {
log.warn("Fail to init config loaders.", e);
} finally {
JdbcUtils.close(inStream);
}
}
/**
* 通过 protocol 获得装载器. 如果没有返回 <code>null</code>.
* @param protocol
* @return 如果没有找到返回<code>null</code>
*/
public static ConfigLoader getConfigLoader(String protocol) {
for (ConfigLoader configLoader : configLoaders.values()) {
if (configLoader.isSupported(protocol)) {
return configLoader;
}
}
return null;
}
public static void addConfigLoader(ConfigLoader configLoader) {
if (configLoaders.putIfAbsent(configLoader.getId(), configLoader) != null) {
log.warn("Duplicate config loader [" + configLoader.getId() + "]");
} else {
if (log.isDebugEnabled()) {
log.debug("Add config loader [" + configLoader.getId() + " = " + configLoader.getClass() + "].");
}
}
}
public static ConfigLoader[] getConfigLoaders() {
return configLoaders.values().toArray(new ConfigLoader[0]);
}
}
@@ -1,110 +0,0 @@
/*
* 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.filter.config.loader.impl;
import com.alibaba.druid.filter.config.loader.ConfigLoader;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
/**
* <pre>
* 通过指定的配置文件路径, 加载该配置. 使用使用NFS共享文件等情况.
* DruidDataSource的connectionProperties必须是 <b>config.file=file:</b> 开头.
* 注意: OSGI下的跨bundle获取资源, 没有测试过
* </pre>
* @author Jonas Yang
*/
public class FileConfigLoader implements ConfigLoader {
private static Log LOG = LogFactory.getLog(FileConfigLoader.class);
public static final String PROTOCOL_PREFIX = "file:";
@Override
public String getId() {
return PROTOCOL_PREFIX;
}
/**
* 如果没有找到配置文件, 返回<code>null</code>
* @param protocol
* @return 如果有找到配置文件返回<code>null</code>
*/
public Properties loadConfig(String protocol) {
if (!isSupported(protocol)) {
throw new IllegalArgumentException("The protocol [" + protocol + "] is not accepted. Protocol must start with [" + PROTOCOL_PREFIX + "].");
}
if(LOG.isDebugEnabled()) {
LOG.debug("Load config file[" + protocol + "] by [" + getId() + "]");
}
Properties properties = new Properties();
InputStream inStream = null;
try {
String filePath = getFilePath(protocol);
File file = new File(filePath);
if (file.exists()) {
inStream = new FileInputStream(file);
} else {
inStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
}
if (inStream == null) {
LOG.error("load config file error, file : " + protocol);
return null;
}
if (isXml(filePath)) {
properties.loadFromXML(inStream);
} else {
properties.load(inStream);
}
return properties;
} catch (Exception ex) {
LOG.error("load config file error, file : " + protocol, ex);
return null;
} finally {
JdbcUtils.close(inStream);
}
}
public String getFilePath(String protocol) {
String filePath = null;
filePath = protocol.substring(PROTOCOL_PREFIX.length());
return filePath;
}
boolean isXml(String filePath) {
return filePath.endsWith(".xml");
}
@Override
public boolean isSupported(String protocol) {
return protocol.toLowerCase().startsWith(PROTOCOL_PREFIX);
}
}
@@ -1,103 +0,0 @@
/*
* 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.filter.config.loader.impl;
import com.alibaba.druid.filter.config.loader.ConfigLoader;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcUtils;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
/**
* <pre>
* 通过HTTP方式获取资源文件.
* DruidDataSource的connectionProperties必须是 <b>config.file=http://</b> 开头.
* </pre>
* @author Jonas Yang
*/
public class HttpConfigLoader implements ConfigLoader {
private static Log LOG = LogFactory.getLog(HttpConfigLoader.class);
public final static String PROTOCOL_PREFIX = "http://";
@Override
public String getId() {
return PROTOCOL_PREFIX;
}
/**
* 如果没有找到资源文件, 返回<code>null</code>
* @param protocol
* @return 如果没有找到资源文件, 返回<code>null</code>
*/
public Properties loadConfig(String protocol) {
if (!isSupported(protocol)) {
throw new IllegalArgumentException("The protocol [" + protocol + "] is not accepted. Protocol must start with [" + PROTOCOL_PREFIX + "].");
}
if(LOG.isDebugEnabled()) {
LOG.debug("Load config file[" + protocol + "] by [" + getId() + "]");
}
Properties properties = new Properties();
InputStream inStream = null;
try {
URL url = getUrl(protocol);
inStream = url.openStream();
if (inStream == null) {
LOG.error("load config file error, file : " + protocol);
return null;
}
if (isXml(url)) {
properties.loadFromXML(inStream);
} else {
properties.load(inStream);
}
return properties;
} catch (Exception ex) {
LOG.error("load config file error, file : " + protocol, ex);
return null;
} finally {
JdbcUtils.close(inStream);
}
}
public URL getUrl(String protocol) throws MalformedURLException {
return new URL(protocol.substring(PROTOCOL_PREFIX.length() - 7));
}
boolean isXml(URL url) {
return url.getPath().endsWith(".xml");
}
@Override
public boolean isSupported(String protocol) {
if (protocol == null) {
return false;
}
return protocol.toLowerCase().startsWith(PROTOCOL_PREFIX);
}
}
@@ -15,7 +15,6 @@
*/
package com.alibaba.druid.support.console;
import java.util.ArrayList;
import java.util.List;
public class TableFormatter {