java調用go、js、python、groovy和Caffeine緩存

一、Caffeine緩存、Caffeine基於java8的高性能,接近最優的緩存庫。

        <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();

    }
}

二、解決 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.

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,不滿足業務需求。
在這裏插入圖片描述

三、java調用go、js、python、groovy

        <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);
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章