<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.4</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>guava</artifactId>
<version>2.8.4</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
import com.github.benmanes.caffeine.cache.*;
import com.github.benmanes.caffeine.guava.CaffeinatedGuava;
import com.google.common.graph.Graph;
import lombok.NonNull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static io.reactivex.internal.util.NotificationLite.getValue;
public class CaffeineCache {
/**
* Caffeine 缓存
*/
public static void test1(){
Cache<String, String> cache = Caffeine.newBuilder()
// 数量上限
.maximumSize(1024)
// 过期机制
.expireAfterWrite(5, TimeUnit.MINUTES)
// 弱引用key
.weakKeys()
// 弱引用value
.weakValues()
// 剔除监听
.removalListener((RemovalListener<String, String>) (key, value, cause) ->
System.out.println("key:" + key + ", value:" + value + ", 删除原因:" + cause.toString()))
.build();
// 将数据放入本地缓存中
cache.put("username", "afei");
cache.put("password", "123456");
// 从本地缓存中取出数据
System.out.println(cache.getIfPresent("username"));
System.out.println(cache.getIfPresent("password"));
//cache.get("blog", key -> {
// 本地缓存没有的话,从数据库或者Redis中获取
//return getValue(key);
//});
}
/**
* Caffeine 异步加载缓存
* @throws ExecutionException
* @throws InterruptedException
* @throws TimeoutException
*/
public static void test2() throws ExecutionException, InterruptedException, TimeoutException {
AsyncLoadingCache<String, String> cache = Caffeine.newBuilder()
// 数量上限
.maximumSize(2)
// 失效时间
.expireAfterWrite(5, TimeUnit.MINUTES)
.refreshAfterWrite(1, TimeUnit.MINUTES)
// 异步加载机制
.buildAsync(new CacheLoader<String, String>() {
@Nullable
@Override
public String load(@NonNull String key) {
return getValue(key);
}
});
System.out.println(cache.get("username").get());
System.out.println(cache.get("password").get(10, TimeUnit.MINUTES));
System.out.println(cache.get("username").get(10, TimeUnit.MINUTES));
System.out.println(cache.get("blog").get());
}
/**
* Guava缓存 转换 Caffeine缓存
*/
public static void test3(){
LoadingCache<String, Graph> graphs = (LoadingCache<String, Graph>) CaffeinatedGuava.build(
Caffeine.newBuilder().maximumSize(10_000),
(CacheLoader<String, Graph>) key -> createExpensiveGraph(key));
System.out.println(graphs.asMap());
}
private static Graph createExpensiveGraph(String key) {
LoadingCache<String, Object> loadingCache = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(keys -> createExpensiveGraph(keys));
return (Graph) loadingCache.get(key);
}
/**
* Guava本地缓存
*/
public static void test4(){
LoadingCache<String, Object> loadingCache = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(key -> createExpensiveGraph(key));
String key = "name";
// 采用同步方式去获取一个缓存和上面的手动方式是一个原理。在build Cache的时候会提供一个createExpensiveGraph函数。
// 查询并在缺失的情况下使用同步的方式来构建一个缓存
Object graph = loadingCache.get(key);
// 获取组key的值返回一个Map
List<String> keys = new ArrayList<>();
keys.add(key);
Map<String, Object> graphs = loadingCache.getAll(keys);
}
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
test1();
test2();
test3();
test4();
}
}
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* 解决Result window is too large, from + size must be less than or equal to: [10000] but was [12910].
* See the scroll api for a more efficient way to request large data sets.
* This limit can be set by changing the [index.max_result_window] index level setting.
*/
@Service
@Slf4j
public class InitElasticSearch implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
//设置ES的初始化分页搜索
Environment env = applicationReadyEvent.getApplicationContext().getEnvironment();
String serverIp = env.getProperty("spring.data.elasticsearch.cluster-nodes");
if (StringUtils.isNotBlank(serverIp)){
String[] split = serverIp.split(":");
String port = env.getProperty("spring.data.elasticsearch.http-port");
String settings = "{\"max_result_window\":\"2000000000\"}";
String url = "http://" + split[0] + ":" + port + "/*/_settings?preserve_existing=true";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", MediaType.APPLICATION_JSON_UTF8_VALUE);
byte[] bytes = HttpUtils.sendRequest(url, headers, settings.getBytes(StandardCharsets.UTF_8), "PUT");
String result = new String(bytes, StandardCharsets.UTF_8);
log.info("初始化ES分页搜索:{}",result);
}
}
将所有的索引设置2000000000
,因为ElasticSearch对from + size的大小进行限制,必须小于等于10000,不满足业务需求。
<dependency>
<groupId>org.python</groupId>
<artifactId>jython</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.1</version>
</dependency>
import java.util.HashMap;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleBindings;
public class JsScriptEngine {
public static String runCode(String jsCode, Map<String, Object> params) {
try {
ScriptEngineManager engineManager= new ScriptEngineManager();
ScriptEngine scriptEngine = engineManager.getEngineByName("JavaScript");
return scriptEngine.eval(jsCode, new SimpleBindings(params)).toString();
} catch (Exception e) {
throw new RuntimeException("执行js脚本出错,"+jsCode);
}
}
public static String runCode(String jsCode) {
return runCode(jsCode, new HashMap<>());
}
}
import com.sun.jna.Structure;
import java.util.ArrayList;
import java.util.List;
/**
* @author nick
*/
public class GoString extends Structure {
public String str;
public GoString() {
}
public GoString(String str) {
this.str = str;
}
@Override
protected List<String> getFieldOrder() {
List<String> fields = new ArrayList<>();
fields.add("str");
return fields;
}
public static class byvalue extends GoString implements Structure.ByValue {
public byvalue(String str) {
super(str);
}
}
public static class byreference extends GoString implements Structure.ByReference {
public byreference(String str) {
super(str);
}
}
}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class FileUtils {
/**
* 读取文件并返回utf8编码的字符流
* @param fileName
* @return
* @throws IOException
*/
public static String readText(String fileName) throws IOException {
File file = new File(fileName);
if (!file.exists()) {
throw new FileNotFoundException();
}
FileInputStream in = new FileInputStream(file);
StringBuffer result = new StringBuffer();
// 指定读取文件时以UTF-8的格式读取
try(BufferedReader br = new BufferedReader(
new InputStreamReader(in, "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) {
result.append(line).append("\n");
}
}
return result.toString();
}
public static String readText(InputStream inputStream) throws IOException {
StringBuffer result = new StringBuffer();
// 指定读取文件时以UTF-8的格式读取
try(BufferedReader br = new BufferedReader(
new InputStreamReader(inputStream, "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) {
result.append(line).append("\n");
}
}
return result.toString();
}
}
import javax.management.MXBean;
/**
* JMX管理
* @author nick
*/
@MXBean
public interface JmxMonitorMXBean {
/**
* print server detail,
* including memory, thread, buff
* @return
*/
void printServer();
/**
* execute JavaScript code
* @param jsCode
* @return
*/
void execJavaScript(String jsCode);
/**
* execute groovy code
* @param groovyCode
* @return
*/
void execGroovyScript(String groovyCode);
/**
* execute go code
* @param goCode
*/
void execGoScript(String goCode);
/**
* execute python code
* @param pythonCode
*/
void execPythonScript(String pythonCode);
}
import com.sun.jna.Native;
import lombok.extern.slf4j.Slf4j;
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.lang.management.*;
import java.util.List;
import static cn.hutool.system.SystemUtil.*;
import static java.lang.management.ManagementFactory.getPlatformMXBeans;
/**
* @author nick
*/
@Slf4j
public class JmxMonitor implements JmxMonitorMXBean {
@Override
public void printServer() {
log.info("运行环境可用cpu核心数量为:{}",Runtime.getRuntime().availableProcessors());
log.info("最大内存为:{}",bytes2MB(Runtime.getRuntime().maxMemory()));
log.info("总内存为:{}",bytes2MB(Runtime.getRuntime().totalMemory()));
log.info("空闲内存为:{}",bytes2MB(Runtime.getRuntime().freeMemory()));
MemoryMXBean memoryMXBean = getMemoryMXBean();
log.info("使用的堆内存:{}",bytes2MB(memoryMXBean.getHeapMemoryUsage().getUsed()));
List<BufferPoolMXBean> buffMXBeans = getPlatformMXBeans(BufferPoolMXBean.class);
buffMXBeans.stream().forEach(e-> log.info("缓冲池:{}, 缓冲池使用:{}, 缓冲池总计:{}",e.getName(), bytes2MB(e.getMemoryUsed()),bytes2MB(e.getTotalCapacity())));
List<GarbageCollectorMXBean> gcMXBeans = getGarbageCollectorMXBeans();
gcMXBeans.stream().forEach(e-> log.info(String.format("%s 发生 %s 次 gc, gc 总共消耗 %s 毫秒", e.getName(), e.getCollectionCount(), e.getCollectionTime())));
ThreadMXBean threadMXBean = getThreadMXBean();
int threadRun = 0;
int threadBlocked = 0;
int threadWaiting = 0;
for (long threadId : threadMXBean.getAllThreadIds()) {
ThreadInfo threadInfo = threadMXBean.getThreadInfo(threadId);
if (threadInfo.getThreadState() == Thread.State.RUNNABLE) {
threadRun++;
}
if (threadInfo.getThreadState() == Thread.State.BLOCKED) {
threadBlocked++;
}
if (threadInfo.getThreadState() == Thread.State.WAITING) {
threadWaiting++;
}
}
log.info(String.format("活跃线程数 %s, 阻塞线程数 %s, 等待线程数 %s", threadRun, threadBlocked, threadWaiting));
}
private static long bytes2MB(long bytes) {
return Math.floorDiv(bytes, 1024 * 1024L);
}
/**
* 实现JS方法
* @param jsCode
*/
@Override
public void execJavaScript(String jsCode){
try {
String jsCodes = JsScriptEngine.runCode(jsCode);
log.info("js代码执行成功,{}",jsCodes);
} catch (Exception e) {
log.error("js代码执行异常,{}",e);
}
}
/**
* 实现Groovy方法
* @param groovyCode
*/
@Override
public void execGroovyScript(String groovyCode) {
try {
ScriptEngineManager engineManager= new ScriptEngineManager();
ScriptEngine scriptEngine = engineManager.getEngineByName("groovy");
Object eval = scriptEngine.eval(groovyCode);
log.info("groovy代码执行成功,{}",eval);
} catch (Exception e) {
log.error("groovy代码执行异常,{}",e);
}
}
/**
* 实现Go方法
* 第一种方式:当你在一个项目中需要同时使用java和go语言时,java语言对应的框架为servicecomb-java-chassis, go对应的框架为go-chassis,他们之间可以通过servicecomb-service-center进行关联。
* 第二种方式:Java调用Golang生成的动态库(dll,so)
* 执行如下命令生成DLL动态链接库 :go build -buildmode=c-shared -o lib.dll .\lib.go
* 执行如下命令生成SO动态库 :go build -buildmode=c-shared -o lib.so .\lib.go
* @param goCode
*/
@Override
public void execGoScript(String goCode) {
try {
String eval = Native.loadLibrary(goCode, String.class);
GoString goString = new GoString(eval);
log.info("go代码执行成功,{}",goString);
} catch (Exception e){
log.error("go代码执行异常,{}",e);
}
}
/**
* 实现Python方法
* @param pythonCode
*/
@Override
public void execPythonScript(String pythonCode) {
try {
PythonInterpreter interpreter = new PythonInterpreter();
PyObject eval = interpreter.eval(pythonCode);
log.info("python代码执行成功,{}",eval);
}catch (Exception e){
log.error("python代码执行异常,{}",e);
}
}
}