线上代码对日志的记录,重要性自不必说。但是怎样记录日志也是有讲究的!
日志可以直接在每个方法中进行日志记录,优点是想怎么记就怎么记,缺点是记日志的代码可 能会超过你的业务代码,可读性急剧下降,这也是日志框架蓬勃发展的源头。
日志也可以通过非业务代码侵入的形式进行记录,具体来说就是合作切面(aop)进行日志记录,好处自然是让业务更纯洁,缺点是运行性能会受到影响。
当然了,前面这些都不是本文的主题。本文的主题是,当你用切面进行日志记录时,然后fastjson是如何把你的业务代码给干掉的。
JsonObject.toJsonString(pj.getArgs()); 这是一个对入参的一个简单打印,至于使用fastjson的原因,自然是因为其输出字符的易读性。args是一个数组。那么这里会有什么问题?普通的参数自然是没有问题了。问题在于,fastjson转换对象为字符串时,要求对象必须是支持可序列化的。为什么要求这样?
解析下fastjson源码过程:
初步进入源码:
// 直接调用json化方法
public static String toJSONString(Object object) {
return toJSONString(object, emptyFilters);
}
// 转到复杂参数的调用
public static String toJSONString(Object object, SerializeFilter[] filters, SerializerFeature... features) {
return toJSONString(object, SerializeConfig.globalInstance, filters, null, DEFAULT_GENERATE_FEATURE, features);
}
// 最终转换方法,1. 获取writer; 2. 处理filter; 3. 将数据定稿writer缓冲; 4. 返回缓冲数据给调用方
public static String toJSONString(Object object, //
SerializeConfig config, //
SerializeFilter[] filters, //
String dateFormat, //
int defaultFeatures, //
SerializerFeature... features) {
SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
try {
JSONSerializer serializer = new JSONSerializer(out, config);
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
serializer.write(object); // 最核心方法
return out.toString();
} finally {
out.close();
}
}
深入内部调用,追根究底:
// 写方法的进一步操作
public final void write(Object object) {
if (object == null) {
out.writeNull();
return;
}
Class<?> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz); // 关键,返回各种对应的序列化器, 如 ObjectArrayCodec
try {
writer.write(this, object, null, null, 0); // 调用对应的序列化器进行处理
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
// 追踪到在运行write方法时出的问题 ObjectArrayCodec
public final void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features)
throws IOException {
SerializeWriter out = serializer.out;
Object[] array = (Object[]) object;
if (object == null) {
out.writeNull(SerializerFeature.WriteNullListAsEmpty);
return;
}
int size = array.length;
int end = size - 1;
if (end == -1) {
out.append("[]");
return;
}
SerialContext context = serializer.context;
serializer.setContext(context, object, fieldName, 0);
try {
Class<?> preClazz = null;
ObjectSerializer preWriter = null;
out.append('[');
if (out.isEnabled(SerializerFeature.PrettyFormat)) {
serializer.incrementIndent();
serializer.println();
for (int i = 0; i < size; ++i) {
if (i != 0) {
out.write(',');
serializer.println();
}
serializer.write(array[i]);
}
serializer.decrementIdent();
serializer.println();
out.write(']');
return;
}
for (int i = 0; i < end; ++i) {
Object item = array[i];
if (item == null) {
out.append("null,");
} else {
if (serializer.containsReference(item)) {
serializer.writeReference(item);
} else {
Class<?> clazz = item.getClass();
if (clazz == preClazz) {
preWriter.write(serializer, item, null, null, 0);
} else {
preClazz = clazz;
preWriter = serializer.getObjectWriter(clazz);
preWriter.write(serializer, item, null, null, 0);
}
}
out.append(',');
}
}
// 最后一个数组需要单独处理
Object item = array[end];
if (item == null) {
out.append("null]");
} else {
if (serializer.containsReference(item)) {
serializer.writeReference(item);
} else {
serializer.writeWithFieldName(item, end);
}
out.append(']');
}
} finally {
serializer.context = context;
}
}
找到最后个出现问题的地方,发现再往下无法再跟踪:
// 外部简单调用
public final void writeWithFieldName(Object object, Object fieldName) {
writeWithFieldName(object, fieldName, null, 0);
}
// 最终报错是在这里
public final void writeWithFieldName(Object object, Object fieldName, Type fieldType, int fieldFeatures) {
try {
if (object == null) {
out.writeNull();
return;
}
Class<?> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz); // ASMSerializer_2_RequestFacade
writer.write(this, object, fieldName, fieldType, fieldFeatures); // 此处使用asm语言写的代码,无法debug, 但是会抛出 IllegalStateException
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
检查最后一次出现的问题,搜索出现的标记,找到动态生成asm代码的文件:
// 动态生成代码 ASMSerializer_2_RequestFacade
public JavaBeanSerializer createJavaBeanSerializer(SerializeBeanInfo beanInfo) throws Exception {
Class<?> clazz = beanInfo.beanType;
if (clazz.isPrimitive()) {
throw new JSONException("unsupportd class " + clazz.getName());
}
JSONType jsonType = clazz.getAnnotation(JSONType.class);
FieldInfo[] unsortedGetters = beanInfo.fields;;
for (FieldInfo fieldInfo : unsortedGetters) {
if (fieldInfo.field == null //
&& fieldInfo.method != null //
&& fieldInfo.method.getDeclaringClass().isInterface()) {
return new JavaBeanSerializer(clazz);
}
}
FieldInfo[] getters = beanInfo.sortedFields;
boolean nativeSorted = beanInfo.sortedFields == beanInfo.fields;
if (getters.length > 256) {
return new JavaBeanSerializer(clazz);
}
for (FieldInfo getter : getters) {
if (!ASMUtils.checkName(getter.getMember().getName())) {
return new JavaBeanSerializer(clazz);
}
}
String className = "ASMSerializer_" + seed.incrementAndGet() + "_" + clazz.getSimpleName();
String packageName = ASMSerializerFactory.class.getPackage().getName();
String classNameType = packageName.replace('.', '/') + "/" + className;
String classNameFull = packageName + "." + className;
ClassWriter cw = new ClassWriter();
cw.visit(V1_5 //
, ACC_PUBLIC + ACC_SUPER //
, classNameType //
, JavaBeanSerializer //
, new String[] { ObjectSerializer } //
);
for (FieldInfo fieldInfo : getters) {
if (fieldInfo.fieldClass.isPrimitive() //
//|| fieldInfo.fieldClass.isEnum() //
|| fieldInfo.fieldClass == String.class) {
continue;
}
new FieldWriter(cw, ACC_PUBLIC, fieldInfo.name + "_asm_fieldType", "Ljava/lang/reflect/Type;") //
.visitEnd();
if (List.class.isAssignableFrom(fieldInfo.fieldClass)) {
new FieldWriter(cw, ACC_PUBLIC, fieldInfo.name + "_asm_list_item_ser_",
ObjectSerializer_desc) //
.visitEnd();
}