Code refactor and refinement for FileInJarReadableDataSource

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
Eric Zhao 2019-04-15 17:02:24 +08:00
parent 882a06007d
commit df27e3ef9d
3 changed files with 48 additions and 61 deletions

View File

@ -31,6 +31,7 @@
</dependencies> </dependencies>
<build> <build>
<finalName>sentinel-demo-dynamic-file-rule</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View File

@ -39,24 +39,24 @@ import java.util.List;
* </p> * </p>
* *
* @author dingq * @author dingq
* @date 2019-03-30
*/ */
public class JarFileDataSourceDemo { public class JarFileDataSourceDemo {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
JarFileDataSourceDemo demo = new JarFileDataSourceDemo(); JarFileDataSourceDemo demo = new JarFileDataSourceDemo();
demo.listenRules(); demo.listenRules();
/* // Start to require tokens, rate will be limited by rule of FlowRule.json in jar.
* Start to require tokens, rate will be limited by rule in FlowRule.json
*/
FlowQpsRunner runner = new FlowQpsRunner(); FlowQpsRunner runner = new FlowQpsRunner();
runner.simulateTraffic(); runner.simulateTraffic();
runner.tick(); runner.tick();
} }
private void listenRules() throws Exception { private void listenRules() throws Exception {
String jarPath = System.getProperty("user.dir") + "/sentinel-demo/sentinel-demo-dynamic-file-rule/target/sentinel-demo-dynamic-file-rule-1.5.1-SNAPSHOT.jar"; // Modify the path with your real path.
// eg: if flowRuleInJarName full path is 'sentinel-demo-dynamic-file-rule-1.5.1-SNAPSHOT.jar!/classes/FlowRule.json', String jarPath = System.getProperty("user.dir") + "/sentinel-demo/sentinel-demo-dynamic-file-rule/target/"
+ "sentinel-demo-dynamic-file-rule.jar";
// eg: if flowRuleInJarName full path is 'sentinel-demo-dynamic-file-rule.jar!/classes/FlowRule.json',
// your flowRuleInJarName is 'classes/FlowRule.json' // your flowRuleInJarName is 'classes/FlowRule.json'
String flowRuleInJarPath = "FlowRule.json"; String flowRuleInJarPath = "FlowRule.json";

View File

@ -16,7 +16,8 @@
package com.alibaba.csp.sentinel.datasource; package com.alibaba.csp.sentinel.datasource;
import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.log.RecordLog;
import java.io.FileNotFoundException; import com.alibaba.csp.sentinel.util.AssertUtil;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -25,65 +26,66 @@ import java.util.jar.JarFile;
/** /**
* <p> * <p>
* A {@link ReadableDataSource} based on jarfile. This class can only read file when it * A {@link ReadableDataSource} based on jar file. This class can only read file initially when it loads file.
* run but will not automatically refresh if it is changed.
* </p> * </p>
* <p> * <p>
* Limitations: Default read buffer size is 1 MB. If file size is greater than * Limitations: Default read buffer size is 1 MB, while max allowed buffer size is 4MB.
* buffer size, exceeding bytes will be ignored. Default charset is UTF-8. * File size should not exceed the buffer size, or exception will be thrown. Default charset is UTF-8.
* </p> * </p>
* *
* @author dingq * @author dingq
* @date 2019-03-30 * @author Eric Zhao
* @since 1.6.0
*/ */
public class FileInJarReadableDataSource<T> extends AutoRefreshDataSource<String, T> { public class FileInJarReadableDataSource<T> extends AbstractDataSource<String, T> {
private static final int MAX_SIZE = 1024 * 1024 * 4;
private static final long DEFAULT_REFRESH_MS = 3000; private static final int MAX_SIZE = 1024 * 1024 * 4;
private static final int DEFAULT_BUF_SIZE = 1024 * 1024; private static final int DEFAULT_BUF_SIZE = 1024 * 1024;
private static final Charset DEFAULT_CHAR_SET = Charset.forName("utf-8"); private static final Charset DEFAULT_CHARSET = Charset.forName("utf-8");
private byte[] buf;
private JarEntry jarEntry;
private JarFile jarFile;
private final Charset charset; private final Charset charset;
private final String jarName; private final String jarName;
private final String fileInJarName; private final String fileInJarName;
private byte[] buf;
private JarEntry jarEntry;
private JarFile jarFile;
/** /**
* @param jarName the jar to read * @param jarName the jar to read
* @param fileInJarName the file in jar to read * @param fileInJarName the file in jar to read
* @param configParser the config decoder (parser) * @param configParser the config decoder (parser)
* @throws FileNotFoundException * @throws IOException if IO failure occurs
*/ */
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser) public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser)
throws IOException { throws IOException {
this(jarName, fileInJarName, configParser, DEFAULT_REFRESH_MS, DEFAULT_BUF_SIZE, DEFAULT_CHAR_SET); this(jarName, fileInJarName, configParser, DEFAULT_BUF_SIZE, DEFAULT_CHARSET);
} }
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, int bufSize) public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser,
throws IOException { int bufSize) throws IOException {
this(jarName, fileInJarName, configParser, DEFAULT_REFRESH_MS, bufSize, DEFAULT_CHAR_SET); this(jarName, fileInJarName, configParser, bufSize, DEFAULT_CHARSET);
} }
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, Charset charset) public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser,
throws IOException {
this(jarName, fileInJarName, configParser, DEFAULT_REFRESH_MS, DEFAULT_BUF_SIZE, charset);
}
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, long recommendRefreshMs, int bufSize,
Charset charset) throws IOException { Charset charset) throws IOException {
super(configParser, recommendRefreshMs); this(jarName, fileInJarName, configParser, DEFAULT_BUF_SIZE, charset);
}
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser,
int bufSize, Charset charset) throws IOException {
super(configParser);
AssertUtil.assertNotBlank(jarName, "jarName cannot be blank");
AssertUtil.assertNotBlank(fileInJarName, "fileInJarName cannot be blank");
if (bufSize <= 0 || bufSize > MAX_SIZE) { if (bufSize <= 0 || bufSize > MAX_SIZE) {
throw new IllegalArgumentException("bufSize must between (0, " + MAX_SIZE + "], but " + bufSize + " get"); throw new IllegalArgumentException("bufSize must between (0, " + MAX_SIZE + "], but " + bufSize + " get");
} }
if (charset == null) { AssertUtil.notNull(charset, "charset can't be null");
throw new IllegalArgumentException("charset can't be null");
}
this.buf = new byte[bufSize]; this.buf = new byte[bufSize];
this.charset = charset; this.charset = charset;
this.jarName = jarName; this.jarName = jarName;
this.fileInJarName = fileInJarName; this.fileInJarName = fileInJarName;
refreshJar(); initializeJar();
firstLoad(); firstLoad();
} }
@ -93,29 +95,14 @@ public class FileInJarReadableDataSource<T> extends AutoRefreshDataSource<String
// Will throw FileNotFoundException later. // Will throw FileNotFoundException later.
RecordLog.warn(String.format("[FileInJarReadableDataSource] File does not exist: %s", jarFile.getName())); RecordLog.warn(String.format("[FileInJarReadableDataSource] File does not exist: %s", jarFile.getName()));
} }
InputStream inputStream = null; try (InputStream inputStream = jarFile.getInputStream(jarEntry)) {
try {
inputStream = jarFile.getInputStream(jarEntry);
if (inputStream.available() > buf.length) { if (inputStream.available() > buf.length) {
throw new IllegalStateException(jarFile.getName() + " file size=" + inputStream.available() throw new IllegalStateException(String.format("Size of file <%s> exceeds the bufSize (%d): %d",
+ ", is bigger than bufSize=" + buf.length + ". Can't read"); jarFile.getName(), buf.length, inputStream.available()));
} }
int len = inputStream.read(buf); int len = inputStream.read(buf);
return new String(buf, 0, len, charset); return new String(buf, 0, len, charset);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception ignore) {
}
}
} }
}
@Override
protected boolean isModified() {
return false;
} }
private void firstLoad() { private void firstLoad() {
@ -123,17 +110,16 @@ public class FileInJarReadableDataSource<T> extends AutoRefreshDataSource<String
T newValue = loadConfig(); T newValue = loadConfig();
getProperty().updateValue(newValue); getProperty().updateValue(newValue);
} catch (Throwable e) { } catch (Throwable e) {
RecordLog.info("loadConfig exception", e); RecordLog.warn("[FileInJarReadableDataSource] Error when loading config", e);
} }
} }
@Override @Override
public void close() throws Exception { public void close() throws Exception {
super.close();
buf = null; buf = null;
} }
private void refreshJar() throws IOException { private void initializeJar() throws IOException {
this.jarFile = new JarFile(jarName); this.jarFile = new JarFile(jarName);
this.jarEntry = jarFile.getJarEntry(fileInJarName); this.jarEntry = jarFile.getJarEntry(fileInJarName);
} }