使用 Jackson 替换 FastJson 组件. (#25)

pull/39/head
chen.ma 4 years ago
parent 9c4441758d
commit a302e5a2ac

@ -1,10 +1,10 @@
package cn.hippo4j.auth.filter;
import cn.hippo4j.auth.toolkit.JwtTokenUtil;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.UserContext;
import cn.hippo4j.common.web.base.Results;
import cn.hippo4j.common.web.exception.ServiceException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -50,7 +50,7 @@ public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
// 返回 Json 形式的错误信息
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
response.getWriter().write(JSON.toJSONString(Results.failure("-1", ex.getMessage())));
response.getWriter().write(JSONUtil.toJSONString(Results.failure("-1", ex.getMessage())));
response.getWriter().flush();
return;
}

@ -21,11 +21,6 @@
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
@ -35,6 +30,11 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
</dependencies>
<build>

@ -0,0 +1,41 @@
package cn.hippo4j.common.api;
import java.util.List;
/**
* Json facade.
*
* @author chen.ma
* @date 2021/12/13 20:01
*/
public interface JsonFacade {
/**
* To JSON string.
*
* @param object
* @return
*/
String toJSONString(Object object);
/**
* Parse object.
*
* @param text
* @param clazz
* @param <T>
* @return
*/
<T> T parseObject(String text, Class<T> clazz);
/**
* Parse array.
*
* @param text
* @param clazz
* @param <T>
* @return
*/
<T> List<T> parseArray(String text, Class<T> clazz);
}

@ -0,0 +1,57 @@
package cn.hippo4j.common.api.impl;
import cn.hippo4j.common.api.JsonFacade;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.CollectionType;
import lombok.SneakyThrows;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
/**
* Jackson util.
*
* @author chen.ma
* @date 2021/12/13 20:02
*/
public class JacksonHandler implements JsonFacade {
private static ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.enable(JsonGenerator.Feature.IGNORE_UNKNOWN);
String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
MAPPER.setDateFormat(new SimpleDateFormat(dateTimeFormat));
MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
@Override
@SneakyThrows
public String toJSONString(Object object) {
return MAPPER.writeValueAsString(object);
}
@Override
@SneakyThrows
public <T> T parseObject(String text, Class<T> clazz) {
JavaType javaType = MAPPER.getTypeFactory().constructType(clazz);
return MAPPER.readValue(text, javaType);
}
@Override
@SneakyThrows
public <T> List<T> parseArray(String text, Class<T> clazz) {
CollectionType collectionType = MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, clazz);
return MAPPER.readValue(text, collectionType);
}
}

@ -1,7 +1,6 @@
package cn.hippo4j.common.toolkit;
import cn.hippo4j.common.constant.Constants;
import com.alibaba.fastjson.JSON;
import cn.hippo4j.common.model.PoolParameter;
import cn.hippo4j.common.model.PoolParameterInfo;
@ -27,7 +26,7 @@ public class ContentUtil {
.setCapacityAlarm(parameter.getCapacityAlarm())
.setLivenessAlarm(parameter.getLivenessAlarm())
.setRejectedType(parameter.getRejectedType());
return JSON.toJSONString(poolInfo);
return JSONUtil.toJSONString(poolInfo);
}
public static String getGroupKey(PoolParameter parameter) {

@ -0,0 +1,47 @@
package cn.hippo4j.common.toolkit;
import cn.hippo4j.common.api.JsonFacade;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hutool.core.util.StrUtil;
import java.util.List;
/**
* JSON util.
*
* @author chen.ma
* @date 2021/12/13 20:27
*/
public class JSONUtil {
private static JsonFacade jsonFacade;
static {
JSONUtil.jsonFacade = ApplicationContextHolder.getBean(JsonFacade.class);
}
public static String toJSONString(Object object) {
if (object == null) {
return null;
}
return jsonFacade.toJSONString(object);
}
public static <T> T parseObject(String text, Class<T> clazz) {
if (StrUtil.isBlank(text)) {
return null;
}
return jsonFacade.parseObject(text, clazz);
}
public static <T> List<T> parseArray(String text, Class<T> clazz) {
if (StrUtil.isBlank(text)) {
return null;
}
return jsonFacade.parseArray(text, clazz);
}
}

@ -51,11 +51,6 @@
<artifactId>hippo4j-common</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-core</artifactId>

@ -1,5 +1,7 @@
package cn.hippo4j.config.config;
import cn.hippo4j.common.api.JsonFacade;
import cn.hippo4j.common.api.impl.JacksonHandler;
import cn.hippo4j.common.config.ApplicationContextHolder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -13,6 +15,11 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class CommonConfig {
@Bean
public JsonFacade jacksonHandler() {
return new JacksonHandler();
}
@Bean
public ApplicationContextHolder simpleApplicationContextHolder() {
return new ApplicationContextHolder();

@ -1,12 +1,12 @@
package cn.hippo4j.config.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import cn.hippo4j.common.model.PoolParameter;
import cn.hippo4j.common.toolkit.JSONUtil;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import cn.hippo4j.common.model.PoolParameter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.util.Date;
@ -26,21 +26,21 @@ public class ConfigAllInfo extends ConfigInfo implements PoolParameter {
/**
* desc
*/
@JSONField(serialize = false)
@JsonIgnore
@TableField(exist = false, fill = FieldFill.UPDATE)
private String desc;
/**
* gmtCreate
*/
@JSONField(serialize = false)
@JsonIgnore
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
/**
* gmtModified
*/
@JSONField(serialize = false)
@JsonIgnore
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
@ -48,13 +48,13 @@ public class ConfigAllInfo extends ConfigInfo implements PoolParameter {
* delFlag
*/
@TableLogic
@JSONField(serialize = false)
@JsonIgnore
@TableField(fill = FieldFill.INSERT)
private Integer delFlag;
@Override
public String toString() {
return JSON.toJSONString(this);
return JSONUtil.toJSONString(this);
}
}

@ -1,8 +1,8 @@
package cn.hippo4j.config.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.io.Serializable;
@ -87,13 +87,13 @@ public class ConfigInfoBase implements Serializable {
/**
* MD5
*/
@JSONField(serialize = false)
@JsonIgnore
private String md5;
/**
* content
*/
@JSONField(serialize = false)
@JsonIgnore
private String content;
}

@ -1,6 +1,6 @@
package cn.hippo4j.config.model.biz.tenant;
import com.alibaba.fastjson.JSON;
import cn.hippo4j.common.toolkit.JSONUtil;
import lombok.Data;
/**
@ -39,7 +39,7 @@ public class TenantUpdateReqDTO {
@Override
public String toString() {
return JSON.toJSONString(this);
return JSONUtil.toJSONString(this);
}
}

@ -2,9 +2,8 @@ package cn.hippo4j.config.monitor;
import cn.hippo4j.common.monitor.MessageTypeEnum;
import cn.hippo4j.common.monitor.RuntimeMessage;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.config.service.biz.HisRunDataService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -29,7 +28,7 @@ public class RuntimeDataResolver extends AbstractMonitorDataExecuteStrategy<Runt
@Override
public void execute(RuntimeMessage message) {
log.info("[{}] Perform monitoring data persistence. content :: {}", this.getClass().getName(), JSON.toJSONString(message, SerializerFeature.PrettyFormat));
log.info("[{}] Perform monitoring data persistence. content :: {}", this.getClass().getName(), JSONUtil.toJSONString(message));
hisRunDataService.save(message);
}

@ -1,16 +1,16 @@
package cn.hippo4j.config.service;
import cn.hippo4j.config.notify.NotifyCenter;
import cn.hutool.core.collection.CollUtil;
import cn.hippo4j.config.service.biz.ConfigService;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.Md5Util;
import cn.hippo4j.config.event.LocalDataChangeEvent;
import cn.hippo4j.config.model.CacheItem;
import cn.hippo4j.config.model.ConfigAllInfo;
import cn.hippo4j.config.notify.NotifyCenter;
import cn.hippo4j.config.service.biz.ConfigService;
import cn.hippo4j.config.toolkit.MapUtil;
import com.alibaba.fastjson.JSON;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
@ -20,6 +20,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Config cache service.
@ -30,20 +31,20 @@ import java.util.concurrent.ConcurrentHashMap;
@Slf4j
public class ConfigCacheService {
private static ConfigService configService = null;
private static ConfigService CONFIG_SERVICE = null;
/**
* TODO: remove
* <p>
* key: message-produce+dynamic-threadpool-example+prescription+192.168.20.227:8088
* key: message-produce+dynamic-threadpool-example+prescription+192.168.20.227:8088_xxx
* val:
* key: 192.168.20.227:8088
* key: 192.168.20.227:8088_xxx
* val: {@link CacheItem}
*/
private static final ConcurrentHashMap<String, Map<String, CacheItem>> CACHE = new ConcurrentHashMap();
private static final ConcurrentHashMap<String, Map<String, CacheItem>> CLIENT_CONFIG_CACHE = new ConcurrentHashMap();
public static boolean isUpdateData(String groupKey, String md5, String ip) {
String contentMd5 = ConfigCacheService.getContentMd5IsNullPut(groupKey, ip);
public static boolean isUpdateData(String groupKey, String md5, String clientIdentify) {
String contentMd5 = ConfigCacheService.getContentMd5IsNullPut(groupKey, clientIdentify);
return Objects.equals(contentMd5, md5);
}
@ -51,38 +52,38 @@ public class ConfigCacheService {
* Get Md5.
*
* @param groupKey
* @param ip
* @param clientIdentify
* @return
*/
private synchronized static String getContentMd5IsNullPut(String groupKey, String ip) {
Map<String, CacheItem> cacheItemMap = Optional.ofNullable(CACHE.get(groupKey)).orElse(Maps.newHashMap());
private synchronized static String getContentMd5IsNullPut(String groupKey, String clientIdentify) {
Map<String, CacheItem> cacheItemMap = Optional.ofNullable(CLIENT_CONFIG_CACHE.get(groupKey)).orElse(Maps.newHashMap());
CacheItem cacheItem = null;
if (CollUtil.isNotEmpty(cacheItemMap) && (cacheItem = cacheItemMap.get(ip)) != null) {
if (CollUtil.isNotEmpty(cacheItemMap) && (cacheItem = cacheItemMap.get(clientIdentify)) != null) {
return cacheItem.md5;
}
if (configService == null) {
configService = ApplicationContextHolder.getBean(ConfigService.class);
if (CONFIG_SERVICE == null) {
CONFIG_SERVICE = ApplicationContextHolder.getBean(ConfigService.class);
}
String[] params = groupKey.split("\\+");
ConfigAllInfo config = configService.findConfigRecentInfo(params);
ConfigAllInfo config = CONFIG_SERVICE.findConfigRecentInfo(params);
if (config != null && !StringUtils.isEmpty(config.getTpId())) {
cacheItem = new CacheItem(groupKey, config);
cacheItemMap.put(ip, cacheItem);
CACHE.put(groupKey, cacheItemMap);
cacheItemMap.put(clientIdentify, cacheItem);
CLIENT_CONFIG_CACHE.put(groupKey, cacheItemMap);
}
return (cacheItem != null) ? cacheItem.md5 : Constants.NULL;
}
public static String getContentMd5(String groupKey) {
if (configService == null) {
configService = ApplicationContextHolder.getBean(ConfigService.class);
if (CONFIG_SERVICE == null) {
CONFIG_SERVICE = ApplicationContextHolder.getBean(ConfigService.class);
}
String[] params = groupKey.split("\\+");
ConfigAllInfo config = configService.findConfigRecentInfo(params);
ConfigAllInfo config = CONFIG_SERVICE.findConfigRecentInfo(params);
if (config == null || StringUtils.isEmpty(config.getTpId())) {
String errorMessage = String.format("config is null. tpId :: %s, itemId :: %s, tenantId :: %s", params[0], params[1], params[2]);
throw new RuntimeException(errorMessage);
@ -91,40 +92,46 @@ public class ConfigCacheService {
return Md5Util.getTpContentMd5(config);
}
public static void updateMd5(String groupKey, String ip, String md5) {
CacheItem cache = makeSure(groupKey, ip);
public static void updateMd5(String groupKey, String identify, String md5) {
CacheItem cache = makeSure(groupKey, identify);
if (cache.md5 == null || !cache.md5.equals(md5)) {
cache.md5 = md5;
String[] params = groupKey.split("\\+");
ConfigAllInfo config = configService.findConfigRecentInfo(params);
ConfigAllInfo config = CONFIG_SERVICE.findConfigRecentInfo(params);
cache.configAllInfo = config;
cache.lastModifiedTs = System.currentTimeMillis();
NotifyCenter.publishEvent(new LocalDataChangeEvent(ip, groupKey));
NotifyCenter.publishEvent(new LocalDataChangeEvent(identify, groupKey));
}
}
public synchronized static CacheItem makeSure(String groupKey, String ip) {
Map<String, CacheItem> ipCacheItemMap = CACHE.get(groupKey);
CacheItem item = ipCacheItemMap.get(ip);
if (null != item) {
Map<String, CacheItem> ipCacheItemMap = CLIENT_CONFIG_CACHE.get(groupKey);
CacheItem item;
if (ipCacheItemMap != null && (item = ipCacheItemMap.get(ip)) != null) {
return item;
}
CacheItem tmp = new CacheItem(groupKey);
Map<String, CacheItem> cacheItemMap = Maps.newHashMap();
cacheItemMap.put(ip, tmp);
CACHE.putIfAbsent(groupKey, cacheItemMap);
CLIENT_CONFIG_CACHE.putIfAbsent(groupKey, cacheItemMap);
return tmp;
}
public static Map<String, CacheItem> getContent(String identification) {
List<String> identificationList = MapUtil.parseMapForFilter(CACHE, identification);
List<String> identificationList = MapUtil.parseMapForFilter(CLIENT_CONFIG_CACHE, identification);
Map<String, CacheItem> returnStrCacheItemMap = Maps.newHashMap();
identificationList.forEach(each -> returnStrCacheItemMap.putAll(CACHE.get(each)));
identificationList.forEach(each -> returnStrCacheItemMap.putAll(CLIENT_CONFIG_CACHE.get(each)));
return returnStrCacheItemMap;
}
public static synchronized Integer getTotal() {
AtomicInteger total = new AtomicInteger();
CLIENT_CONFIG_CACHE.forEach((key, val) -> total.addAndGet(val.values().size()));
return total.get();
}
/**
* Remove config cache.
*
@ -132,10 +139,10 @@ public class ConfigCacheService {
*/
public synchronized static void removeConfigCache(String groupKey) {
// 模糊搜索
List<String> identificationList = MapUtil.parseMapForFilter(CACHE, groupKey);
List<String> identificationList = MapUtil.parseMapForFilter(CLIENT_CONFIG_CACHE, groupKey);
for (String cacheMapKey : identificationList) {
Map<String, CacheItem> removeCacheItem = CACHE.remove(cacheMapKey);
log.info("Remove invalidated config cache. config info :: {}", JSON.toJSONString(removeCacheItem));
Map<String, CacheItem> removeCacheItem = CLIENT_CONFIG_CACHE.remove(cacheMapKey);
log.info("Remove invalidated config cache. config info :: {}", JSONUtil.toJSONString(removeCacheItem));
}
}

@ -1,21 +1,22 @@
package cn.hippo4j.config.service;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.Md5Util;
import cn.hippo4j.common.web.base.Results;
import cn.hippo4j.config.event.Event;
import cn.hippo4j.config.event.LocalDataChangeEvent;
import cn.hippo4j.config.notify.NotifyCenter;
import cn.hippo4j.config.toolkit.Md5ConfigUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import cn.hippo4j.config.notify.listener.Subscriber;
import cn.hippo4j.config.toolkit.ConfigExecutor;
import cn.hippo4j.config.toolkit.MapUtil;
import cn.hippo4j.config.toolkit.Md5ConfigUtil;
import cn.hippo4j.config.toolkit.RequestUtil;
import cn.hippo4j.common.toolkit.Md5Util;
import cn.hippo4j.common.web.base.Results;
import cn.hippo4j.config.event.Event;
import cn.hippo4j.config.event.LocalDataChangeEvent;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
@ -113,8 +114,8 @@ public class LongPollingService {
parseMapForFilter.forEach(each -> {
if (clientSub.clientMd5Map.containsKey(each)) {
getRetainIps().put(clientSub.ip, System.currentTimeMillis());
ConfigCacheService.updateMd5(each, clientSub.ip, ConfigCacheService.getContentMd5(identity));
getRetainIps().put(clientSub.clientIdentify, System.currentTimeMillis());
ConfigCacheService.updateMd5(each, clientSub.clientIdentify, ConfigCacheService.getContentMd5(each));
iter.remove();
clientSub.sendResponse(Arrays.asList(groupKey));
}
@ -126,18 +127,14 @@ public class LongPollingService {
}
}
public static boolean isSupportLongPolling(HttpServletRequest req) {
return null != req.getHeader(LONG_POLLING_HEADER);
}
private static boolean isFixedPolling() {
return SwitchService.getSwitchBoolean(SwitchService.FIXED_POLLING, false);
}
private static int getFixedPollingInterval() {
return SwitchService.getSwitchInteger(SwitchService.FIXED_POLLING_INTERVAL, FIXED_POLLING_INTERVAL_MS);
}
/**
* Add long polling client.
*
* @param req
* @param rsp
* @param clientMd5Map
* @param probeRequestSize
*/
public void addLongPollingClient(HttpServletRequest req, HttpServletResponse rsp, Map<String, String> clientMd5Map,
int probeRequestSize) {
String str = req.getHeader(LONG_POLLING_HEADER);
@ -159,14 +156,17 @@ public class LongPollingService {
}
}
String ip = RequestUtil.getRemoteIp(req);
String clientIdentify = RequestUtil.getClientIdentify(req);
final AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0L);
ConfigExecutor.executeLongPolling(new ClientLongPolling(asyncContext, clientMd5Map, ip, probeRequestSize, timeout - delayTime, appName));
ConfigExecutor.executeLongPolling(new ClientLongPolling(asyncContext, clientMd5Map, clientIdentify, probeRequestSize, timeout - delayTime, appName));
}
/**
* Regularly check the configuration for changes.
*/
class ClientLongPolling implements Runnable {
final AsyncContext asyncContext;
@ -175,7 +175,7 @@ public class LongPollingService {
final long createTime;
final String ip;
final String clientIdentify;
final String appName;
@ -185,10 +185,10 @@ public class LongPollingService {
Future<?> asyncTimeoutFuture;
public ClientLongPolling(AsyncContext asyncContext, Map<String, String> clientMd5Map, String ip, int probeRequestSize, long timeout, String appName) {
public ClientLongPolling(AsyncContext asyncContext, Map<String, String> clientMd5Map, String clientIdentify, int probeRequestSize, long timeout, String appName) {
this.asyncContext = asyncContext;
this.clientMd5Map = clientMd5Map;
this.ip = ip;
this.clientIdentify = clientIdentify;
this.probeRequestSize = probeRequestSize;
this.timeoutTime = timeout;
this.appName = appName;
@ -199,7 +199,7 @@ public class LongPollingService {
public void run() {
asyncTimeoutFuture = ConfigExecutor.scheduleLongPolling(() -> {
try {
getRetainIps().put(ClientLongPolling.this.ip, System.currentTimeMillis());
getRetainIps().put(ClientLongPolling.this.clientIdentify, System.currentTimeMillis());
allSubs.remove(ClientLongPolling.this);
if (isFixedPolling()) {
@ -221,6 +221,11 @@ public class LongPollingService {
allSubs.add(this);
}
/**
* Send response.
*
* @param changedGroups Changed thread pool group key
*/
private void sendResponse(List<String> changedGroups) {
// Cancel time out task.
if (null != asyncTimeoutFuture) {
@ -229,6 +234,11 @@ public class LongPollingService {
generateResponse(changedGroups);
}
/**
* Generate async response.
*
* @param changedGroups Changed thread pool group key
*/
private void generateResponse(List<String> changedGroups) {
if (null == changedGroups) {
// Tell web container to send http response.
@ -239,17 +249,15 @@ public class LongPollingService {
HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
try {
String respStr = Md5Util.compareMd5ResultString(changedGroups);
String resultStr = JSON.toJSONString(Results.success(respStr));
String respStr = buildRespStr(changedGroups);
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache,no-store");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println(resultStr);
asyncContext.complete();
response.getWriter().println(respStr);
} catch (Exception ex) {
log.error(ex.toString(), ex);
log.error("Response client failed to return data.", ex);
} finally {
asyncContext.complete();
}
}
@ -260,20 +268,66 @@ public class LongPollingService {
return retainIps;
}
/**
* Generate sync response.
*
* @param response response
* @param changedGroups Changed thread pool group key
*/
private void generateResponse(HttpServletResponse response, List<String> changedGroups) {
if (!CollectionUtils.isEmpty(changedGroups)) {
if (CollUtil.isNotEmpty(changedGroups)) {
try {
final String changedGroupKeStr = Md5ConfigUtil.compareMd5ResultString(changedGroups);
final String respString = JSON.toJSONString(Results.success(changedGroupKeStr));
String respStr = buildRespStr(changedGroups);
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache,no-store");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println(respString);
response.getWriter().println(respStr);
} catch (Exception ex) {
log.error(ex.toString(), ex);
log.error("Response client failed to return data.", ex);
}
}
}
/**
* Build resp str.
*
* @param changedGroups Changed thread pool group key
* @return
*/
@SneakyThrows
private String buildRespStr(List<String> changedGroups) {
String changedGroupStr = Md5Util.compareMd5ResultString(changedGroups);
String respStr = JSONUtil.toJSONString(Results.success(changedGroupStr));
return respStr;
}
/**
* Is support long polling.
*
* @param req
* @return
*/
public static boolean isSupportLongPolling(HttpServletRequest req) {
return null != req.getHeader(LONG_POLLING_HEADER);
}
/**
* Is fixed polling.
*
* @return
*/
private static boolean isFixedPolling() {
return SwitchService.getSwitchBoolean(SwitchService.FIXED_POLLING, false);
}
/**
* Get fixed polling interval.
*
* @return
*/
private static int getFixedPollingInterval() {
return SwitchService.getSwitchInteger(SwitchService.FIXED_POLLING_INTERVAL, FIXED_POLLING_INTERVAL_MS);
}
}

@ -3,6 +3,7 @@ package cn.hippo4j.config.service.biz.impl;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.toolkit.ConditionUtil;
import cn.hippo4j.common.toolkit.ContentUtil;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.Md5Util;
import cn.hippo4j.config.event.LocalDataChangeEvent;
import cn.hippo4j.config.mapper.ConfigInfoMapper;
@ -15,7 +16,6 @@ import cn.hippo4j.config.service.biz.ConfigService;
import cn.hippo4j.config.toolkit.BeanUtil;
import cn.hippo4j.tools.logrecord.annotation.LogRecord;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
@ -62,18 +62,22 @@ public class ConfigServiceImpl implements ConfigService {
public ConfigAllInfo findConfigRecentInfo(String... params) {
ConfigAllInfo resultConfig;
ConfigAllInfo configInstance = null;
LambdaQueryWrapper<ConfigInstanceInfo> instanceQueryWrapper = Wrappers.lambdaQuery(ConfigInstanceInfo.class)
.eq(ConfigInstanceInfo::getInstanceId, params[3])
.orderByDesc(ConfigInstanceInfo::getGmtCreate)
.last("LIMIT 1");
ConfigInstanceInfo instanceInfo = configInstanceMapper.selectOne(instanceQueryWrapper);
if (instanceInfo != null) {
String content = instanceInfo.getContent();
configInstance = JSON.parseObject(content, ConfigAllInfo.class);
configInstance.setContent(content);
configInstance.setGmtCreate(instanceInfo.getGmtCreate());
configInstance.setMd5(Md5Util.getTpContentMd5(configInstance));
String instanceId = params[3];
if (StrUtil.isNotBlank(instanceId)) {
LambdaQueryWrapper<ConfigInstanceInfo> instanceQueryWrapper = Wrappers.lambdaQuery(ConfigInstanceInfo.class)
.eq(ConfigInstanceInfo::getInstanceId, params[3])
.orderByDesc(ConfigInstanceInfo::getGmtCreate)
.last("LIMIT 1");
ConfigInstanceInfo instanceInfo = configInstanceMapper.selectOne(instanceQueryWrapper);
if (instanceInfo != null) {
String content = instanceInfo.getContent();
configInstance = JSONUtil.parseObject(content, ConfigAllInfo.class);
configInstance.setContent(content);
configInstance.setGmtCreate(instanceInfo.getGmtCreate());
configInstance.setMd5(Md5Util.getTpContentMd5(configInstance));
}
}
ConfigAllInfo configAllInfo = findConfigAllInfo(params[0], params[1], params[2]);

@ -50,8 +50,8 @@ public class Md5ConfigUtil {
public static List<String> compareMd5(HttpServletRequest request, Map<String, String> clientMd5Map) {
List<String> changedGroupKeys = new ArrayList();
clientMd5Map.forEach((key, val) -> {
String remoteIp = RequestUtil.getRemoteIp(request);
boolean isUpdateData = ConfigCacheService.isUpdateData(key, val, remoteIp);
String clientIdentify = RequestUtil.getClientIdentify(request);
boolean isUpdateData = ConfigCacheService.isUpdateData(key, val, clientIdentify);
if (!isUpdateData) {
changedGroupKeys.add(key);
}

@ -1,6 +1,6 @@
package cn.hippo4j.config.toolkit;
import org.springframework.util.StringUtils;
import cn.hutool.core.util.StrUtil;
import javax.servlet.http.HttpServletRequest;
@ -20,14 +20,9 @@ public class RequestUtil {
private static final String X_FORWARDED_FOR_SPLIT_SYMBOL = ",";
public static String getRemoteIp(HttpServletRequest request) {
String xForwardedFor = request.getHeader(X_FORWARDED_FOR);
if (!StringUtils.isEmpty(xForwardedFor)) {
return xForwardedFor.split(X_FORWARDED_FOR_SPLIT_SYMBOL)[0].trim();
}
String nginxHeader = request.getHeader(X_REAL_IP);
String ipPort = request.getHeader(LONG_PULLING_CLIENT_IDENTIFICATION);
return StringUtils.isEmpty(nginxHeader) ? ipPort : nginxHeader;
public static String getClientIdentify(HttpServletRequest request) {
String identify = request.getHeader(LONG_PULLING_CLIENT_IDENTIFICATION);
return StrUtil.isBlank(identify) ? "" : identify;
}
}

@ -36,11 +36,6 @@
<artifactId>logging-interceptor</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-common</artifactId>

@ -3,6 +3,7 @@ package cn.hippo4j.starter.alarm;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.model.PoolParameterInfo;
import cn.hippo4j.common.toolkit.GroupKey;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.web.base.Result;
import cn.hippo4j.starter.config.BootstrapProperties;
import cn.hippo4j.starter.core.DynamicThreadPoolExecutor;
@ -10,7 +11,6 @@ import cn.hippo4j.starter.core.GlobalThreadPoolManage;
import cn.hippo4j.starter.remote.HttpAgent;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
@ -125,8 +125,8 @@ public class BaseSendMessageService implements InitializingBean, SendMessageServ
}
if (result != null && result.isSuccess() && result.getData() != null) {
String resultDataStr = JSON.toJSONString(result.getData());
List<ThreadPoolNotify> resultData = JSON.parseArray(resultDataStr, ThreadPoolNotify.class);
String resultDataStr = JSONUtil.toJSONString(result.getData());
List<ThreadPoolNotify> resultData = JSONUtil.parseArray(resultDataStr, ThreadPoolNotify.class);
resultData.forEach(each -> ALARM_NOTIFY_CONFIG.put(each.getNotifyKey(), each.getNotifyList()));
ALARM_NOTIFY_CONFIG.forEach((key, val) ->

@ -2,6 +2,7 @@ package cn.hippo4j.starter.alarm.wechat;
import cn.hippo4j.common.model.InstanceInfo;
import cn.hippo4j.common.model.PoolParameterInfo;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.starter.alarm.NotifyDTO;
import cn.hippo4j.starter.alarm.NotifyPlatformEnum;
import cn.hippo4j.starter.alarm.SendMessageHandler;
@ -13,7 +14,6 @@ import cn.hippo4j.starter.wrapper.DynamicThreadPoolWrapper;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.google.common.base.Joiner;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -155,7 +155,7 @@ public class WeChatSendMessageHandler implements SendMessageHandler {
markdown.setContent(text);
weChatReq.setMarkdown(markdown);
HttpRequest.post(serverUrl).body(JSON.toJSONString(weChatReq)).execute();
HttpRequest.post(serverUrl).body(JSONUtil.toJSONString(weChatReq)).execute();
} catch (Exception ex) {
log.error("WeChat failed to send message", ex);
}

@ -1,5 +1,7 @@
package cn.hippo4j.starter.config;
import cn.hippo4j.common.api.JsonFacade;
import cn.hippo4j.common.api.impl.JacksonHandler;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.starter.controller.PoolRunStateController;
import cn.hippo4j.starter.core.ConfigService;
@ -105,6 +107,11 @@ public class DynamicThreadPoolAutoConfiguration {
return new HttpScheduledHealthCheck(httpAgent);
}
@Bean
public JsonFacade jacksonHandler() {
return new JacksonHandler();
}
}

@ -3,12 +3,12 @@ package cn.hippo4j.starter.core;
import cn.hippo4j.common.model.PoolParameterInfo;
import cn.hippo4j.common.toolkit.ContentUtil;
import cn.hippo4j.common.toolkit.GroupKey;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.web.base.Result;
import cn.hippo4j.starter.remote.HttpAgent;
import cn.hippo4j.starter.remote.ServerHealthCheck;
import cn.hippo4j.starter.toolkit.thread.ThreadFactoryBuilder;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
@ -110,7 +110,7 @@ public class ClientWorker {
try {
String content = getServerConfig(namespace, itemId, tpId, 3000L);
CacheData cacheData = cacheMap.get(tpId);
String poolContent = ContentUtil.getPoolContent(JSON.parseObject(content, PoolParameterInfo.class));
String poolContent = ContentUtil.getPoolContent(JSONUtil.parseObject(content, PoolParameterInfo.class));
cacheData.setContent(poolContent);
} catch (Exception ex) {
// ignore
@ -191,7 +191,7 @@ public class ClientWorker {
Result result = agent.httpGetByConfig(CONFIG_CONTROLLER_PATH, null, params, readTimeout);
if (result.isSuccess()) {
return result.getData().toString();
return JSONUtil.toJSONString(result.getData());
}
log.error("[Sub server] namespace :: {}, itemId :: {}, tpId :: {}, result code :: {}",
@ -217,18 +217,16 @@ public class ClientWorker {
String[] keyArr = dataIdAndGroup.split(WORD_SEPARATOR);
String dataId = keyArr[0];
String group = keyArr[1];
if (keyArr.length == 2) {
updateList.add(GroupKey.getKey(dataId, group));
log.info("[{}] [Polling resp] config changed. dataId={}, group={}", dataId, group);
} else if (keyArr.length == 3) {
if (keyArr.length == 3) {
String tenant = keyArr[2];
updateList.add(GroupKey.getKeyTenant(dataId, group, tenant));
log.info("[Polling resp] config changed. dataId={}, group={}, tenant={}", dataId, group, tenant);
log.info("Refresh thread pool changed. [{}]", dataId);
} else {
log.error("[{}] [Polling resp] invalid dataIdAndGroup error {}", dataIdAndGroup);
log.error("[{}] [Polling resp] invalid dataIdAndGroup error.", dataIdAndGroup);
}
}
}
return updateList;
}
@ -251,7 +249,7 @@ public class ClientWorker {
String serverConfig = null;
try {
serverConfig = getServerConfig(namespace, itemId, tpId, 3000L);
PoolParameterInfo poolInfo = JSON.parseObject(serverConfig, PoolParameterInfo.class);
PoolParameterInfo poolInfo = JSONUtil.parseObject(serverConfig, PoolParameterInfo.class);
cacheData.setContent(ContentUtil.getPoolContent(poolInfo));
} catch (Exception ex) {
log.error("[Cache Data] Error. Service Unavailable :: {}", ex.getMessage());

@ -3,6 +3,7 @@ package cn.hippo4j.starter.core;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.common.model.PoolParameterInfo;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.web.base.Result;
import cn.hippo4j.starter.common.CommonDynamicThreadPool;
import cn.hippo4j.starter.config.BootstrapProperties;
@ -11,7 +12,6 @@ import cn.hippo4j.starter.toolkit.thread.QueueTypeEnum;
import cn.hippo4j.starter.toolkit.thread.RejectedTypeEnum;
import cn.hippo4j.starter.toolkit.thread.ThreadPoolBuilder;
import cn.hippo4j.starter.wrapper.DynamicThreadPoolWrapper;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
@ -108,26 +108,29 @@ public final class DynamicThreadPoolPostProcessor implements BeanPostProcessor {
try {
result = httpAgent.httpGetByConfig(Constants.CONFIG_CONTROLLER_PATH, null, queryStrMap, 5000L);
if (result.isSuccess() && result.getData() != null && (ppi = JSON.toJavaObject((JSON) result.getData(), PoolParameterInfo.class)) != null) {
// 使用相关参数创建线程池
BlockingQueue workQueue = QueueTypeEnum.createBlockingQueue(ppi.getQueueType(), ppi.getCapacity());
poolExecutor = ThreadPoolBuilder.builder()
.dynamicPool()
.workQueue(workQueue)
.threadFactory(tpId)
.poolThreadSize(ppi.getCoreSize(), ppi.getMaxSize())
.keepAliveTime(ppi.getKeepAliveTime(), TimeUnit.SECONDS)
.rejected(RejectedTypeEnum.createPolicy(ppi.getRejectedType()))
.alarmConfig(ppi.getIsAlarm(), ppi.getCapacityAlarm(), ppi.getLivenessAlarm())
.build();
if (poolExecutor instanceof DynamicExecutorConfigurationSupport) {
TaskDecorator taskDecorator = ((DynamicThreadPoolExecutor) dynamicThreadPoolWrap.getExecutor()).getTaskDecorator();
((DynamicThreadPoolExecutor) poolExecutor).setTaskDecorator(taskDecorator);
if (result.isSuccess() && result.getData() != null) {
String resultJsonStr = JSONUtil.toJSONString(result.getData());
if ((ppi = JSONUtil.parseObject(resultJsonStr, PoolParameterInfo.class)) != null) {
// 使用相关参数创建线程池
BlockingQueue workQueue = QueueTypeEnum.createBlockingQueue(ppi.getQueueType(), ppi.getCapacity());
poolExecutor = ThreadPoolBuilder.builder()
.dynamicPool()
.workQueue(workQueue)
.threadFactory(tpId)
.poolThreadSize(ppi.getCoreSize(), ppi.getMaxSize())
.keepAliveTime(ppi.getKeepAliveTime(), TimeUnit.SECONDS)
.rejected(RejectedTypeEnum.createPolicy(ppi.getRejectedType()))
.alarmConfig(ppi.getIsAlarm(), ppi.getCapacityAlarm(), ppi.getLivenessAlarm())
.build();
if (poolExecutor instanceof DynamicExecutorConfigurationSupport) {
TaskDecorator taskDecorator = ((DynamicThreadPoolExecutor) dynamicThreadPoolWrap.getExecutor()).getTaskDecorator();
((DynamicThreadPoolExecutor) poolExecutor).setTaskDecorator(taskDecorator);
}
dynamicThreadPoolWrap.setExecutor(poolExecutor);
isSubscribe = true;
}
dynamicThreadPoolWrap.setExecutor(poolExecutor);
isSubscribe = true;
}
} catch (Exception ex) {
poolExecutor = dynamicThreadPoolWrap.getExecutor() != null ? dynamicThreadPoolWrap.getExecutor() : CommonDynamicThreadPool.getInstance(tpId);

@ -1,11 +1,11 @@
package cn.hippo4j.starter.core;
import cn.hippo4j.common.model.PoolParameterInfo;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.starter.alarm.ThreadPoolAlarmManage;
import cn.hippo4j.starter.toolkit.thread.QueueTypeEnum;
import cn.hippo4j.starter.toolkit.thread.RejectedTypeEnum;
import cn.hippo4j.starter.toolkit.thread.ResizableCapacityLinkedBlockIngQueue;
import com.alibaba.fastjson.JSON;
import cn.hippo4j.common.model.PoolParameterInfo;
import cn.hippo4j.starter.alarm.ThreadPoolAlarmManage;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit;
public class ThreadPoolDynamicRefresh {
public static void refreshDynamicPool(String content) {
PoolParameterInfo parameter = JSON.parseObject(content, PoolParameterInfo.class);
PoolParameterInfo parameter = JSONUtil.parseObject(content, PoolParameterInfo.class);
ThreadPoolAlarmManage.sendPoolConfigChange(parameter);
ThreadPoolDynamicRefresh.refreshDynamicPool(parameter);
}

@ -1,6 +1,6 @@
package cn.hippo4j.starter.toolkit;
import com.alibaba.fastjson.JSON;
import cn.hippo4j.common.toolkit.JSONUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
@ -63,7 +63,7 @@ public class HttpClientUtil {
*/
public <T> T restApiGet(String url, Class<T> clazz) {
String resp = get(url);
return JSON.parseObject(resp, clazz);
return JSONUtil.parseObject(resp, clazz);
}
/**
@ -77,7 +77,7 @@ public class HttpClientUtil {
@SneakyThrows
public <T> T restApiGetHealth(String url, Class<T> clazz) {
String resp = new String(doGet(url), "utf-8");
return JSON.parseObject(resp, clazz);
return JSONUtil.parseObject(resp, clazz);
}
/**
@ -92,7 +92,7 @@ public class HttpClientUtil {
public <T> T restApiGet(String url, Map<String, String> queryString, Class<T> clazz) {
String fullUrl = buildUrl(url, queryString);
String resp = get(fullUrl);
return JSON.parseObject(resp, clazz);
return JSONUtil.parseObject(resp, clazz);
}
/**
@ -121,7 +121,7 @@ public class HttpClientUtil {
*/
public <T> T restApiPost(String url, Object body, Class<T> clazz) {
String resp = restApiPost(url, body);
return JSON.parseObject(resp, clazz);
return JSONUtil.parseObject(resp, clazz);
}
/**
@ -159,7 +159,7 @@ public class HttpClientUtil {
@SneakyThrows
private String doPost(String url, Object body) {
String jsonBody = JSON.toJSONString(body);
String jsonBody = JSONUtil.toJSONString(body);
RequestBody requestBody = RequestBody.create(jsonMediaType, jsonBody);
Request request = new Request.Builder()
.url(url)
@ -205,7 +205,7 @@ public class HttpClientUtil {
throw new RuntimeException(msg);
}
return JSON.parseObject(resp.body().string(), clazz);
return JSONUtil.parseObject(resp.body().string(), clazz);
}
@SneakyThrows
@ -227,7 +227,7 @@ public class HttpClientUtil {
log.error(msg);
throw new RuntimeException(msg);
}
return JSON.parseObject(resp.body().string(), clazz);
return JSONUtil.parseObject(resp.body().string(), clazz);
}
}

@ -26,7 +26,7 @@
<properties>
<java.version>1.8</java.version>
<revision>1.0.0-RC3</revision>
<revision>1.0.0-SNAPSHOT</revision>
<dozer.version>6.5.0</dozer.version>
<guava.version>29.0-jre</guava.version>
@ -38,6 +38,7 @@
<transmittable-thread-local.version>2.12.1</transmittable-thread-local.version>
<forest.version>1.5.11</forest.version>
<jjwt.version>0.9.0</jjwt.version>
<jackson-bom.version>2.11.1</jackson-bom.version>
<dingtalk-sdk.version>1.0.1</dingtalk-sdk.version>
@ -195,6 +196,13 @@
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>${spring-boot.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>

Loading…
Cancel
Save