我的場(chǎng)景:配置文件變更,不用重啟程序语卤,環(huán)境變量即可生效
但是我又不想監(jiān)聽整個(gè)文件夾追逮,只想針對(duì)某個(gè)或某些文件做監(jiān)聽酪刀,自己抽象了個(gè)實(shí)現(xiàn)類
先上代碼
接口
import java.io.File;
public interface DynamicConfiguration {
void addListener(File file);
void removeListener(File file);
void start();
void close();
}
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import java.io.File;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j
public abstract class AbstractDynamicConfiguration implements DynamicConfiguration, Runnable{
private static final String DEFAULT_THREAD_POOL_PREFIX_NAME = "thread-pool.prefix.workers";
private static final int DEFAULT_THREAD_POOL_SIZE = 1;
private static final long DEFAULT_KEEP_ALIVE_TIME = TimeUnit.MINUTES.toMillis(1);
private final List<FileInfo> fileInfoChain;
private final ThreadPoolExecutor workersThreadPool;
private volatile Boolean running;
private final ReentrantLock lock = new ReentrantLock();
public AbstractDynamicConfiguration(String threadPoolPrefixName, int threadPoolSize, long keepAliveTime) {
this.workersThreadPool = initWorkersThreadPool(threadPoolPrefixName, threadPoolSize, keepAliveTime);
this.fileInfoChain = new CopyOnWriteArrayList<>();
this.running = false;
}
public AbstractDynamicConfiguration() {
this(DEFAULT_THREAD_POOL_PREFIX_NAME, DEFAULT_THREAD_POOL_SIZE, DEFAULT_KEEP_ALIVE_TIME);
}
@Override
public void start() {
this.running = true;
this.workersThreadPool.execute(this::run);
}
@Override
public void close() {
this.running = false;
fileInfoChain.clear();
if (!workersThreadPool.isShutdown()) {
workersThreadPool.shutdown();
}
}
@Override
public void addListener(File file) {
fileInfoChain.add(new FileInfo(file));
if(log.isInfoEnabled()) {
log.info("Reload enabled, watching {}...", file.getPath());
}
}
@Override
public void removeListener(File file) {
fileInfoChain.remove(new FileInfo(file));
}
protected ThreadPoolExecutor initWorkersThreadPool(String threadPoolPrefixName,
int threadPoolSize,
long keepAliveTime) {
return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, keepAliveTime,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory(threadPoolPrefixName, true));
}
@Override
public void run() {
while (this.running) {
lock.lock();
try {
var iterator = fileInfoChain.iterator();
while (iterator.hasNext()) {
try {
var fileInfo = iterator.next();
File newFile = new File(fileInfo.getFile().toURI());
if (newFile.lastModified() != fileInfo.getLastModified()) {
fileInfo.updateLastModified(newFile.lastModified());
try {
dynamicConfiguration(newFile);
}finally {
if(log.isDebugEnabled()) {
log.debug("The gateway environment variable has been reloaded");
}
}
}
} catch (Exception e) {
close();
}
}
} finally {
lock.unlock();
}
if(!this.running) {
break;
}
try {
Thread.sleep(10000L);
} catch (InterruptedException var3) {
close();
}
}
}
public abstract void dynamicConfiguration(File file);
@Data
@Accessors(chain = true)
class FileInfo {
private File file;
private Long lastModified;
public FileInfo(File file) {
this.file = file;
this.lastModified = file.lastModified();
}
public void updateLastModified(Long lastModified){
this.lastModified = lastModified;
}
}
class NamedThreadFactory implements ThreadFactory {
protected final AtomicInteger mThreadNum = new AtomicInteger(1);
protected final String mPrefix;
protected final boolean mDaemon;
protected final ThreadGroup mGroup;
public NamedThreadFactory(String prefix, boolean daemon) {
mPrefix = prefix + "-thread-";
mDaemon = daemon;
SecurityManager s = System.getSecurityManager();
mGroup = (s == null) ? Thread.currentThread().getThreadGroup() : s.getThreadGroup();
}
@Override
public Thread newThread(Runnable runnable) {
String name = mPrefix + mThreadNum.getAndIncrement();
Thread ret = new Thread(mGroup, runnable, name, 0);
ret.setDaemon(mDaemon);
return ret;
}
}
}
使用:
第一步:實(shí)現(xiàn)抽象類里面得dynamicConfiguration方法
第二步:添加自己需要監(jiān)聽得文件
第三步:?jiǎn)?dòng)監(jiān)聽程序
image.png
效果:
image.png
image.png