upgrade to fastjson2. #2498

pull/2519/head
hengyunabc 2 years ago
parent a1e7fe59b6
commit b73475fe08

@ -57,8 +57,8 @@
<shadedPattern>${arthas.deps.package}.io.netty</shadedPattern> <shadedPattern>${arthas.deps.package}.io.netty</shadedPattern>
</relocation> </relocation>
<relocation> <relocation>
<pattern>com.alibaba.fastjson</pattern> <pattern>com.alibaba.fastjson2</pattern>
<shadedPattern>${arthas.deps.package}.com.alibaba.fastjson</shadedPattern> <shadedPattern>${arthas.deps.package}.com.alibaba.fastjson2</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
<filters> <filters>
@ -204,8 +204,8 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson2</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>ognl</groupId> <groupId>ognl</groupId>
@ -258,7 +258,6 @@
<scope>provided</scope> <scope>provided</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

@ -10,8 +10,8 @@ import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.taobao.arthas.core.command.Constants; import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.DashboardModel; import com.taobao.arthas.core.command.model.DashboardModel;
import com.taobao.arthas.core.command.model.GcInfoVO; import com.taobao.arthas.core.command.model.GcInfoVO;

@ -1,6 +1,6 @@
package com.taobao.arthas.core.distribution; package com.taobao.arthas.core.distribution;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.taobao.arthas.core.command.model.Countable; import com.taobao.arthas.core.command.model.Countable;
import com.taobao.arthas.core.command.model.ResultModel; import com.taobao.arthas.core.command.model.ResultModel;
import org.slf4j.Logger; import org.slf4j.Logger;

@ -2,7 +2,7 @@ package com.taobao.arthas.core.distribution.impl;
import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.taobao.arthas.core.command.model.ResultModel; import com.taobao.arthas.core.command.model.ResultModel;
import com.taobao.arthas.core.distribution.PackingResultDistributor; import com.taobao.arthas.core.distribution.PackingResultDistributor;
import com.taobao.arthas.core.shell.session.Session; import com.taobao.arthas.core.shell.session.Session;

@ -2,7 +2,7 @@ package com.taobao.arthas.core.distribution.impl;
import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.taobao.arthas.core.command.model.ResultModel; import com.taobao.arthas.core.command.model.ResultModel;
import com.taobao.arthas.core.distribution.DistributorOptions; import com.taobao.arthas.core.distribution.DistributorOptions;
import com.taobao.arthas.core.distribution.ResultConsumer; import com.taobao.arthas.core.distribution.ResultConsumer;

@ -34,8 +34,8 @@ import com.alibaba.bytekit.asm.instrument.InstrumentTransformer;
import com.alibaba.bytekit.asm.matcher.SimpleClassMatcher; import com.alibaba.bytekit.asm.matcher.SimpleClassMatcher;
import com.alibaba.bytekit.utils.AsmUtils; import com.alibaba.bytekit.utils.AsmUtils;
import com.alibaba.bytekit.utils.IOUtils; import com.alibaba.bytekit.utils.IOUtils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson2.JSONWriter;
import com.taobao.arthas.common.AnsiLog; import com.taobao.arthas.common.AnsiLog;
import com.taobao.arthas.common.ArthasConstants; import com.taobao.arthas.common.ArthasConstants;
import com.taobao.arthas.common.PidUtils; import com.taobao.arthas.common.PidUtils;
@ -177,14 +177,9 @@ public class ArthasBootstrap {
} }
private void initFastjson() { private void initFastjson() {
// disable fastjson circular reference feature
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
// add date format option for fastjson
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteDateUseDateFormat.getMask();
// ignore getter error #1661 // ignore getter error #1661
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.IgnoreErrorGetter.getMask();
// #2081 // #2081
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteNonStringKeyAsString.getMask(); JSON.config(JSONWriter.Feature.IgnoreErrorGetter, JSONWriter.Feature.WriteNonStringKeyAsString);
} }
private void initBeans() { private void initBeans() {

@ -64,13 +64,11 @@ public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequ
path = "/index.html"; path = "/index.html";
} }
boolean isHttpApiResponse = false;
boolean isFileResponseFinished = false; boolean isFileResponseFinished = false;
try { try {
//handle http restful api //handle http restful api
if ("/api".equals(path)) { if ("/api".equals(path)) {
response = httpApiHandler.handle(ctx, request); response = httpApiHandler.handle(ctx, request);
isHttpApiResponse = true;
} }
//handle webui requests //handle webui requests
@ -106,16 +104,6 @@ public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequ
if (!isFileResponseFinished) { if (!isFileResponseFinished) {
ChannelFuture future = writeResponse(ctx, response); ChannelFuture future = writeResponse(ctx, response);
future.addListener(ChannelFutureListener.CLOSE); future.addListener(ChannelFutureListener.CLOSE);
//reuse http api response buf
if (isHttpApiResponse && response instanceof DefaultFullHttpResponse) {
final HttpResponse finalResponse = response;
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
httpApiHandler.onCompleted((DefaultFullHttpResponse) finalResponse);
}
});
}
} }
} }
} }

@ -2,11 +2,8 @@ package com.taobao.arthas.core.shell.term.impl.http.api;
import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig; import com.alibaba.fastjson2.filter.ValueFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.alibaba.fastjson.util.IOUtils;
import com.taobao.arthas.common.ArthasConstants; import com.taobao.arthas.common.ArthasConstants;
import com.taobao.arthas.common.PidUtils; import com.taobao.arthas.common.PidUtils;
import com.taobao.arthas.core.command.model.*; import com.taobao.arthas.core.command.model.*;
@ -34,7 +31,6 @@ import com.taobao.arthas.core.shell.term.impl.http.session.HttpSession;
import com.taobao.arthas.core.shell.term.impl.http.session.HttpSessionManager; import com.taobao.arthas.core.shell.term.impl.http.session.HttpSessionManager;
import com.taobao.arthas.core.util.ArthasBanner; import com.taobao.arthas.core.util.ArthasBanner;
import com.taobao.arthas.core.util.DateUtils; import com.taobao.arthas.core.util.DateUtils;
import com.taobao.arthas.core.util.JsonUtils;
import com.taobao.arthas.core.util.StringUtils; import com.taobao.arthas.core.util.StringUtils;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.ByteBufOutputStream;
@ -68,25 +64,11 @@ public class HttpApiHandler {
private final JobController jobController; private final JobController jobController;
private final HistoryManager historyManager; private final HistoryManager historyManager;
private int jsonBufferSize = 1024 * 256;
private int poolSize = 8;
private ArrayBlockingQueue<ByteBuf> byteBufPool = new ArrayBlockingQueue<ByteBuf>(poolSize);
private ArrayBlockingQueue<char[]> charsBufPool = new ArrayBlockingQueue<char[]>(poolSize);
private ArrayBlockingQueue<byte[]> bytesPool = new ArrayBlockingQueue<byte[]>(poolSize);
public HttpApiHandler(HistoryManager historyManager, SessionManager sessionManager) { public HttpApiHandler(HistoryManager historyManager, SessionManager sessionManager) {
this.historyManager = historyManager; this.historyManager = historyManager;
this.sessionManager = sessionManager; this.sessionManager = sessionManager;
commandManager = this.sessionManager.getCommandManager(); commandManager = this.sessionManager.getCommandManager();
jobController = this.sessionManager.getJobController(); jobController = this.sessionManager.getJobController();
//init buf pool
JsonUtils.setSerializeWriterBufferThreshold(jsonBufferSize);
for (int i = 0; i < poolSize; i++) {
byteBufPool.offer(Unpooled.buffer(jsonBufferSize));
charsBufPool.offer(new char[jsonBufferSize]);
bytesPool.offer(new byte[jsonBufferSize]);
}
} }
public HttpResponse handle(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { public HttpResponse handle(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
@ -113,77 +95,13 @@ public class HttpApiHandler {
} }
result.setRequestId(requestId); result.setRequestId(requestId);
byte[] jsonBytes = JSON.toJSONBytes(result, JSON_FILTERS);
//http response content // create http response
ByteBuf content = null; DefaultFullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(),
//fastjson buf HttpResponseStatus.OK, Unpooled.wrappedBuffer(jsonBytes));
char[] charsBuf = null; response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8");
byte[] bytesBuf = null; return response;
try {
//apply response content buf first
content = byteBufPool.poll(2000, TimeUnit.MILLISECONDS);
if (content == null) {
throw new ApiException("get response content buf failure");
}
//apply fastjson buf from pool
charsBuf = charsBufPool.poll();
bytesBuf = bytesPool.poll();
if (charsBuf == null || bytesBuf == null) {
throw new ApiException("get json buf failure");
}
JsonUtils.setSerializeWriterBufThreadLocal(charsBuf, bytesBuf);
//create http response
DefaultFullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(),
HttpResponseStatus.OK, content.retain());
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8");
writeResult(response, result);
return response;
} catch (Exception e) {
//response is discarded
if (content != null) {
content.release();
byteBufPool.offer(content);
}
throw e;
} finally {
//give back json buf to pool
JsonUtils.setSerializeWriterBufThreadLocal(null, null);
if (charsBuf != null) {
charsBufPool.offer(charsBuf);
}
if (bytesBuf != null) {
bytesPool.offer(bytesBuf);
}
}
}
public void onCompleted(DefaultFullHttpResponse httpResponse) {
ByteBuf content = httpResponse.content();
content.clear();
if (content.capacity() == jsonBufferSize) {
if (!byteBufPool.offer(content)) {
content.release();
}
} else {
//replace content ByteBuf
content.release();
if (byteBufPool.remainingCapacity() > 0) {
byteBufPool.offer(Unpooled.buffer(jsonBufferSize));
}
}
}
private void writeResult(DefaultFullHttpResponse response, Object result) throws IOException {
ByteBufOutputStream out = new ByteBufOutputStream(response.content());
try {
JSON.writeJSONString(out, IOUtils.UTF8, result, SerializeConfig.globalInstance, JSON_FILTERS, null, JSON.DEFAULT_GENERATE_FEATURE);
} catch (IOException e) {
logger.error("write json to response failed", e);
throw e;
}
} }
private ApiRequest parseRequest(String requestBody) throws ApiException { private ApiRequest parseRequest(String requestBody) throws ApiException {

@ -1,6 +1,6 @@
package com.taobao.arthas.core.shell.term.impl.http.api; package com.taobao.arthas.core.shell.term.impl.http.api;
import com.alibaba.fastjson.serializer.ValueFilter; import com.alibaba.fastjson2.filter.ValueFilter;
import com.taobao.arthas.core.command.model.ObjectVO; import com.taobao.arthas.core.command.model.ObjectVO;
import com.taobao.arthas.core.util.StringUtils; import com.taobao.arthas.core.util.StringUtils;
import com.taobao.arthas.core.view.ObjectView; import com.taobao.arthas.core.view.ObjectView;
@ -12,8 +12,7 @@ import com.taobao.arthas.core.view.ObjectView;
public class ObjectVOFilter implements ValueFilter { public class ObjectVOFilter implements ValueFilter {
@Override @Override
public Object process(Object object, String name, Object value) { public Object apply(Object object, String name, Object value) {
if (value instanceof ObjectVO) { if (value instanceof ObjectVO) {
ObjectVO vo = (ObjectVO) value; ObjectVO vo = (ObjectVO) value;
String resultStr = StringUtils.objectToString(vo.needExpand() ? new ObjectView(vo).draw() : value); String resultStr = StringUtils.objectToString(vo.needExpand() ? new ObjectView(vo).draw() : value);

@ -1,93 +0,0 @@
package com.taobao.arthas.core.util;
import com.alibaba.fastjson.serializer.SerializeWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
/**
* @author gongdewei 2020/5/15
*/
public class JsonUtils {
private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);
private static Field serializeWriterBufLocalField;
private static Field serializeWriterBytesBufLocal;
private static Field serializeWriterBufferThreshold;
/**
* Set Fastjson SerializeWriter Buffer Threshold
* @param value
*/
public static void setSerializeWriterBufferThreshold(int value) {
Class<SerializeWriter> clazz = SerializeWriter.class;
try {
if (serializeWriterBufferThreshold == null) {
serializeWriterBufferThreshold = clazz.getDeclaredField("BUFFER_THRESHOLD");
}
serializeWriterBufferThreshold.setAccessible(true);
serializeWriterBufferThreshold.set(null, value);
} catch (Throwable e) {
logger.error("update SerializeWriter.BUFFER_THRESHOLD value failed", e);
}
}
/**
* Set Fastjson SerializeWriter ThreadLocal value
* @param bufSize
*/
public static void setSerializeWriterBufThreadLocal(int bufSize) {
Class<SerializeWriter> clazz = SerializeWriter.class;
try {
//set threadLocal value
if (serializeWriterBufLocalField == null) {
serializeWriterBufLocalField = clazz.getDeclaredField("bufLocal");
}
serializeWriterBufLocalField.setAccessible(true);
ThreadLocal<char[]> bufLocal = (ThreadLocal<char[]>) serializeWriterBufLocalField.get(null);
char[] charsLocal = bufLocal.get();
if (charsLocal == null || charsLocal.length < bufSize) {
bufLocal.set(new char[bufSize]);
}
if (serializeWriterBytesBufLocal == null) {
serializeWriterBytesBufLocal = clazz.getDeclaredField("bytesBufLocal");
}
serializeWriterBytesBufLocal.setAccessible(true);
ThreadLocal<byte[]> bytesBufLocal = (ThreadLocal<byte[]>) serializeWriterBytesBufLocal.get(null);
byte[] bytesLocal = bytesBufLocal.get();
if (bytesLocal == null || bytesLocal.length < bufSize) {
bytesBufLocal.set(new byte[bufSize]);
}
} catch (Throwable e) {
logger.error("update SerializeWriter.BUFFER_THRESHOLD value failed", e);
}
}
/**
* Set Fastjson SerializeWriter ThreadLocal value
*/
public static void setSerializeWriterBufThreadLocal(char[] charsBuf, byte[] bytesBuf) {
Class<SerializeWriter> clazz = SerializeWriter.class;
try {
//set threadLocal value
if (serializeWriterBufLocalField == null) {
serializeWriterBufLocalField = clazz.getDeclaredField("bufLocal");
}
serializeWriterBufLocalField.setAccessible(true);
ThreadLocal<char[]> bufLocal = (ThreadLocal<char[]>) serializeWriterBufLocalField.get(null);
bufLocal.set(charsBuf);
if (serializeWriterBytesBufLocal == null) {
serializeWriterBytesBufLocal = clazz.getDeclaredField("bytesBufLocal");
}
serializeWriterBytesBufLocal.setAccessible(true);
ThreadLocal<byte[]> bytesBufLocal = (ThreadLocal<byte[]>) serializeWriterBytesBufLocal.get(null);
bytesBufLocal.set(bytesBuf);
} catch (Throwable e) {
logger.error("update SerializeWriter.BUFFER_THRESHOLD value failed", e);
}
}
}

@ -1,7 +1,7 @@
package com.taobao.arthas.core.util; package com.taobao.arthas.core.util;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.taobao.arthas.common.IOUtils; import com.taobao.arthas.common.IOUtils;
import java.io.BufferedReader; import java.io.BufferedReader;

@ -2,8 +2,8 @@ package com.taobao.arthas.core.view;
import com.alibaba.arthas.deps.org.slf4j.Logger; import com.alibaba.arthas.deps.org.slf4j.Logger;
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson2.JSONWriter;
import com.taobao.arthas.common.ArthasConstants; import com.taobao.arthas.common.ArthasConstants;
import com.taobao.arthas.core.GlobalOptions; import com.taobao.arthas.core.GlobalOptions;
import com.taobao.arthas.core.command.model.ObjectVO; import com.taobao.arthas.core.command.model.ObjectVO;
@ -54,7 +54,7 @@ public class ObjectView implements View {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
try { try {
if (GlobalOptions.isUsingJson) { if (GlobalOptions.isUsingJson) {
return JSON.toJSONString(object, SerializerFeature.IgnoreErrorGetter); return JSON.toJSONString(object, JSONWriter.Feature.IgnoreErrorGetter);
} }
renderObject(object, 0, deep, buf); renderObject(object, 0, deep, buf);
return buf.toString(); return buf.toString();

@ -136,9 +136,9 @@
<version>0.0.13</version> <version>0.0.13</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson2</artifactId>
<version>1.2.83_noneautotype</version> <version>2.0.29</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.taobao.text</groupId> <groupId>com.taobao.text</groupId>

Loading…
Cancel
Save