解决server sdk反复初始化时内存泄漏问题

This commit is contained in:
heavyrian2012
2025-08-25 11:11:12 +08:00
parent 3f8fd7e5e0
commit cd03583dab
6 changed files with 66 additions and 27 deletions
@@ -9,12 +9,14 @@ import cn.wildfirechat.sdk.utilities.ChannelHttpUtils;
import com.google.gson.Gson; import com.google.gson.Gson;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import java.io.Closeable;
import java.io.IOException;
import java.util.List; import java.util.List;
import static cn.wildfirechat.proto.ProtoConstants.ApplicationType.ApplicationType_Channel; import static cn.wildfirechat.proto.ProtoConstants.ApplicationType.ApplicationType_Channel;
//仅专业版支持,社区版不支持 //仅专业版支持,社区版不支持
public class ChannelServiceApi { public class ChannelServiceApi implements Closeable {
private final ChannelHttpUtils channelHttpUtils; private final ChannelHttpUtils channelHttpUtils;
public ChannelServiceApi(String imurl, String channelId, String secret) { public ChannelServiceApi(String imurl, String channelId, String secret) {
@@ -66,7 +68,6 @@ public class ChannelServiceApi {
return channelHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class); return channelHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);
} }
//仅专业版支持
public IMResult<String> recallMessage(long messageUid) throws Exception { public IMResult<String> recallMessage(long messageUid) throws Exception {
String path = APIPath.Channel_Msg_Recall; String path = APIPath.Channel_Msg_Recall;
RecallMessageData messageData = new RecallMessageData(); RecallMessageData messageData = new RecallMessageData();
@@ -74,7 +75,6 @@ public class ChannelServiceApi {
return channelHttpUtils.httpJsonPost(path, messageData, String.class); return channelHttpUtils.httpJsonPost(path, messageData, String.class);
} }
//仅专业版支持
public IMResult<Void> republishMessage(long messageUid, List<String> targets) throws Exception { public IMResult<Void> republishMessage(long messageUid, List<String> targets) throws Exception {
String path = APIPath.Channel_Msg_Republish; String path = APIPath.Channel_Msg_Republish;
RepublishChannelMessageData messageData = new RepublishChannelMessageData(); RepublishChannelMessageData messageData = new RepublishChannelMessageData();
@@ -131,4 +131,8 @@ public class ChannelServiceApi {
return configData; return configData;
} }
@Override
public void close() throws IOException {
channelHttpUtils.close();
}
} }
@@ -21,7 +21,7 @@ import static cn.wildfirechat.proto.ProtoConstants.ChannelState.*;
import static cn.wildfirechat.proto.ProtoConstants.SystemSettingType.Group_Max_Member_Count; import static cn.wildfirechat.proto.ProtoConstants.SystemSettingType.Group_Max_Member_Count;
public class Main { public class Main {
private static boolean commercialServer = false; private static boolean commercialServer = true;
private static boolean advanceVoip = false; private static boolean advanceVoip = false;
private static boolean robotMomentsEnabled = false; private static boolean robotMomentsEnabled = false;
private static boolean momentsEnabled = false; private static boolean momentsEnabled = false;
@@ -1413,6 +1413,7 @@ public class Main {
System.exit(-1); System.exit(-1);
} }
//使用完需要释放
RobotService robotService = new RobotService(IMUrl, robotId, robotSecret); RobotService robotService = new RobotService(IMUrl, robotId, robotSecret);
//*********************************************** //***********************************************
@@ -1812,6 +1813,9 @@ public class Main {
System.exit(-1); System.exit(-1);
} }
} }
//使用完需要释放
robotService.close();
} }
//***测试频道API功能,仅专业版支持*** //***测试频道API功能,仅专业版支持***
@@ -1882,7 +1886,7 @@ public class Main {
} }
//2. 初始化api,注意端口是80,不是18080 //2. 初始化api,注意端口是80,不是18080 //使用完需要释放
ChannelServiceApi channelServiceApi = new ChannelServiceApi(IMUrl, channelId, secret); ChannelServiceApi channelServiceApi = new ChannelServiceApi(IMUrl, channelId, secret);
@@ -2038,6 +2042,9 @@ public class Main {
} }
OutputApplicationConfigData config = channelServiceApi.getApplicationSignature(); OutputApplicationConfigData config = channelServiceApi.getApplicationSignature();
System.out.println(config); System.out.println(config);
//使用完需要释放
channelServiceApi.close();
} }
static void testSensitiveApi() throws Exception { static void testSensitiveApi() throws Exception {
List<String> words = Arrays.asList("a","b","c"); List<String> words = Arrays.asList("a","b","c");
@@ -8,11 +8,13 @@ import cn.wildfirechat.sdk.model.IMResult;
import cn.wildfirechat.sdk.utilities.RobotHttpUtils; import cn.wildfirechat.sdk.utilities.RobotHttpUtils;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import java.io.Closeable;
import java.io.IOException;
import java.util.List; import java.util.List;
import static cn.wildfirechat.proto.ProtoConstants.ApplicationType.ApplicationType_Robot; import static cn.wildfirechat.proto.ProtoConstants.ApplicationType.ApplicationType_Robot;
public class RobotService { public class RobotService implements Closeable {
private final RobotHttpUtils robotHttpUtils; private final RobotHttpUtils robotHttpUtils;
public RobotService(String url, String robotId, String robotSecret) { public RobotService(String url, String robotId, String robotSecret) {
@@ -423,4 +425,9 @@ public class RobotService {
requestPojo.rl = removeList; requestPojo.rl = removeList;
return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class); return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);
} }
@Override
public void close() throws IOException {
robotHttpUtils.close();
}
} }
@@ -41,28 +41,30 @@ public class AdminHttpUtils extends JsonUtils {
init(url, secret, 15000); init(url, secret, 15000);
} }
public static void init(String url, String secret, int timeout) { public static synchronized void init(String url, String secret, int timeout) {
adminUrl = url.trim(); adminUrl = url.trim();
adminSecret = secret.trim(); adminSecret = secret.trim();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); if(httpClient == null) {
cm.setValidateAfterInactivity(1000); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
int connectTimeout = 15000; // 连接超时时间 cm.setValidateAfterInactivity(1000);
int connectionRequestTimeout = 3000; // 从连接池获取连接的超时时间 int connectTimeout = 15000; // 连接超时时间
RequestConfig requestConfig = RequestConfig.custom() int connectionRequestTimeout = 3000; // 从连接池获取连接的超时时间
.setConnectTimeout(connectTimeout) RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(timeout) .setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectionRequestTimeout) .setSocketTimeout(timeout)
.build(); .setConnectionRequestTimeout(connectionRequestTimeout)
.build();
httpClient = HttpClients.custom() httpClient = HttpClients.custom()
.setDefaultRequestConfig(requestConfig) .setDefaultRequestConfig(requestConfig)
.setConnectionManager(cm) .setConnectionManager(cm)
.evictExpiredConnections() .evictExpiredConnections()
.evictIdleConnections(60L, TimeUnit.SECONDS) .evictIdleConnections(60L, TimeUnit.SECONDS)
.setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE) .setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE)
.setMaxConnTotal(100) .setMaxConnTotal(100)
.setMaxConnPerRoute(50) .setMaxConnPerRoute(50)
.build(); .build();
}
} }
public static <T> IMResult<T> httpGet(String path, Class<T> clazz) throws Exception { public static <T> IMResult<T> httpGet(String path, Class<T> clazz) throws Exception {
@@ -20,6 +20,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.net.MalformedURLException; import java.net.MalformedURLException;
@@ -28,7 +30,7 @@ import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class ChannelHttpUtils extends JsonUtils { public class ChannelHttpUtils extends JsonUtils implements Closeable {
private static final Logger LOG = LoggerFactory.getLogger(ChannelHttpUtils.class); private static final Logger LOG = LoggerFactory.getLogger(ChannelHttpUtils.class);
public static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); public static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
@@ -156,4 +158,9 @@ public class ChannelHttpUtils extends JsonUtils {
public String getChannelSecret() { public String getChannelSecret() {
return channelSecret; return channelSecret;
} }
@Override
public void close() throws IOException {
httpClient.close();
}
} }
@@ -3,29 +3,35 @@ package cn.wildfirechat.sdk.utilities;
import cn.wildfirechat.sdk.model.IMResult; import cn.wildfirechat.sdk.model.IMResult;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import ikidou.reflect.TypeBuilder;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class RobotHttpUtils extends JsonUtils { public class RobotHttpUtils extends JsonUtils implements Closeable {
private static final Logger LOG = LoggerFactory.getLogger(RobotHttpUtils.class); private static final Logger LOG = LoggerFactory.getLogger(RobotHttpUtils.class);
public static final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); public static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
@@ -78,6 +84,7 @@ public class RobotHttpUtils extends JsonUtils {
.build(); .build();
} }
public <T> IMResult<T> httpJsonPost(String path, Object object, Class<T> clazz) throws Exception{ public <T> IMResult<T> httpJsonPost(String path, Object object, Class<T> clazz) throws Exception{
if (isNullOrEmpty(url) || isNullOrEmpty(path)) { if (isNullOrEmpty(url) || isNullOrEmpty(path)) {
LOG.error("Not init IM SDK correctly. Do you forget init it?"); LOG.error("Not init IM SDK correctly. Do you forget init it?");
@@ -154,4 +161,9 @@ public class RobotHttpUtils extends JsonUtils {
public String getRobotSecret() { public String getRobotSecret() {
return robotSecret; return robotSecret;
} }
@Override
public void close() throws IOException {
httpClient.close();
}
} }