文章目录
- 1 集合工具类
- 1.1 `java.util.``Collections`
- 1.1.1 基本操作
- 1.1.2 转换线程安全集合
- 1.2 org.springframework.util.CollectionUtils
- 1.3 org.apache.commons.collections.CollectionUtils
- 1.4 org.apache.commons.lang.ArrayUtils
- 1.5 org.apache.commons.lang3.ArrayUtils
- 1.6 com.google.common.collect.Lists
- 2 文件流工具类
- 2.1 org.apache.commons.io.IOUtils
- 2.2 org.apache.commons.io.FileUtils
- 2.3 org.apache.commons.io.FilenameUtils
- 2.4 org.springframework.util.FileCopyUtils
- 2.5 org.springframework.util.ResourceUtils
- 2.6 org.springframework.util.StreamUtils
- 3 字符串工具类
- 3.1 org.apache.commons.lang.StringUtils
- 3.2 org.apache.commons.lang3.StringUtils
- 3.3 org.springframework.util.StringUtils
- 3.4 org.apache.commons.lang3.StringEscapeUtils(废弃)
- 4 对象属性及反射工具类
- 4.1 java.util.Objects
- 4.2 org.apache.http.util.EntityUtils
- 4.3 org.apache.commons.beanutils.PropertyUtils
- 4.4 org.apache.commons.beanutils.BeanUtils
- 4.5 org.springframework.beans.BeanUtils
- 4.6 org.springframework.util.ClassUtils
- 4.7 org.springframework.util.ReflectionUtils
- 4.8 org.springframework.util.**ObjectUtils**
- 4.9 org.springframework.util.**AopUtils**
- 4.10 org.springframework.util.**AopContext**
- 5 网络序列化工具类
- 5.1 org.apache.http.client.utils.URLEncodedUtils
- 5.2 org.apache.http.HttpStatus
- 5.3 org.springframework.util.SerializationUtils
- 6 加解密工具类
- 6.1 org.apache.commons.codec.digest.DigestUtils
- 6.2 org.springframework.util.Base64Utils
- 6.3 java.nio.charset.StandardCharsets
- 7 其他工具类
- 7.1 org.apache.commons.lang3.BooleanUtils
- 7.2 org.springframework.util.Assert
- 7.2.1 断言参数是否为空
- 7.2.2 断言集合是否为空
- 7.2.3 断言条件是否为空
- 7.3 org.slf4j.MDC
1 集合工具类
1.1 java.util.``Collections
使用的基本list示意
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);
1.1.1 基本操作
Collections.sort(list);//升序
Collections.reverse(list);//降序
Collections.max(list);//获取最大值
Collections.min(list);//获取最小值
Collections.emptyList();//空集合
Collections.binarySearch(list, 3);//二分查找
Collections.unmodifiableList(list);//转换成不可修改集合
1.1.2 转换线程安全集合
我们都知道,java中的很多集合,比如:ArrayList、LinkedList、HashMap、HashSet等,都是线程不安全的。
换句话说,这些集合在多线程的环境中,添加数据会出现异常。
这时,可以用**Collections的synchronizedxxx
**方法,将这些线程不安全的集合,直接转换成线程安全集合。例如
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);
List<Integer> integers = Collections.synchronizedList(list);//将ArrayList转换成线程安全集合
System.out.println(integers);
它的底层会创建**SynchronizedRandomAccessList
或者SynchronizedList
类,这两个类的很多方法都会用synchronized
**加锁
1.2 org.springframework.util.CollectionUtils
集合判断工具
判断 List/Set 是否为空
boolean isEmpty(Collection<?> collection)
判断 Map 是否为空
boolean isEmpty(Map<?,?> map)
判断 List/Set 中是否包含某个对象
boolean containsInstance(Collection<?> collection, Object element)
以迭代器的方式,判断 List/Set 中是否包含某个对象
boolean contains(Iterator<?> iterator, Object element)
判断 List/Set 是否包含某些对象中的任意一个
boolean containsAny(Collection<?> source, Collection<?> candidates)
判断 List/Set 中的每个元素是否唯一。即 List/Set 中不存在重复元素
boolean hasUniqueObject(Collection<?> collection)
集合操作工具
将 Array 中的元素都添加到 List/Set 中
<E> void mergeArrayIntoCollection(Object array, Collection<E> collection)
将 Properties 中的键值对都添加到 Map 中
<K,V> void mergePropertiesIntoMap(Properties props, Map<K,V> map)
返回 List 中最后一个元素
<T> T lastElement(List<T> list)
返回 Set 中最后一个元素
<T> T lastElement(Set<T> set)
返回参数 candidates 中第一个存在于参数 source 中的元素
<E> E findFirstMatch(Collection<?> source, Collection<E> candidates)
返回 List/Set 中指定类型的元素
<T> T findValueOfType(Collection<?> collection, Class<T> type)
返回 List/Set 中指定类型的元素。如果第一种类型未找到,则查找第二种类型,以此类推
Object findValueOfType(Collection<?> collection, Class<?>[] types)
返回 List/Set 中元素的类型
Class<?> findCommonElementType(Collection<?> collection)
1.3 org.apache.commons.collections.CollectionUtils
常用方法:
常用方法:
CollectionUtils.isEmpty();//集合判空
CollectionUtils.union(list, list2);//获取并集
CollectionUtils.intersection(list, list2);//获取交集
CollectionUtils.disjunction(list, list2);//获取交集的补集
CollectionUtils.subtract(list, list2);//获取差集
CollectionUtils.select:根据条件筛选集合元素
CollectionUtils.transform:根据指定方法处理集合元素,类似List的map()
CollectionUtils.filter:过滤元素,雷瑟List的filter()
CollectionUtils.find:基本和select一样
CollectionUtils.collect:和transform 差不多一样,但是返回新数组
CollectionUtils.forAllDo:调用每个元素的指定方法
1.4 org.apache.commons.lang.ArrayUtils
contains:是否包含某字符串
addAll:添加整个数组
clone:克隆一个数组
isEmpty:是否空数组
add:向数组添加元素
subarray:截取数组
indexOf:查找某个元素的下标
isEquals:比较数组是否相等
toObject:基础类型数据数组转换为对应的Object数组
1.5 org.apache.commons.lang3.ArrayUtils
contains:是否包含某个字符串
addAll:添加整个数组
clone:克隆一个数组
isEmpty:是否空数组
add:向数组添加元素
subarray:截取数组
indexOf:查找某个元素的下标
isEquals:比较数组是否相等
toObject:基础类型数据数组转换为对应的Object数组
1.6 com.google.common.collect.Lists
Lists.newArrayList();//创建空集合
Lists.newArrayList(1, 2, 3);//快速初始化集合
Lists.cartesianProduct(list1,list2);//笛卡尔积
Lists.partition(list, 2);//分页,将一个大集合分成若干个小集合
Lists.transform(list, x -> x.toUpperCase());//把某个集合转换成另外一个接口,可以使用Lists的transform方法
Lists.reverse(list);//颠倒顺序
2 文件流工具类
2.1 org.apache.commons.io.IOUtils
closeQuietly:关闭一个IO流、socket、或者selector且不抛出异常,通常放在finally块
toString:读取文件,转换IO流、 Uri、 byte[]为String,例:IOUtils.toString(new FileInputStream("/temp/a.txt"), StandardCharsets.UTF_8);
copy:文件拷贝,IO流数据复制,从输入流写到输出流中,最大支持2GB,例:IOUtils.copy(new FileInputStream("/temp/a.txt"), new FileOutputStream("/temp/b.txt"));
toByteArray:读取文件内容到字节数组,从输入流、URI获取byte[],IOUtils.toByteArray(new FileInputStream("/temp/a.txt"));
write:写入文件,把字节. 字符等写入输出流,例:IOUtils.write(str, new FileOutputStream("/temp/b.tx"), StandardCharsets.UTF_8);
toInputStream:把字符转换为输入流
readLines:从输入流中读取多行数据,返回List<String>
copyLarge:同copy,支持2GB以上数据的复制
lineIterator:从输入流返回一个迭代器,根据参数要求读取的数据量,全部读取,如果数据不够,则失败
其他常用方法:
2.2 org.apache.commons.io.FileUtils
deleteDirectory:删除文件夹
readFileToString:以字符形式读取文件内容
deleteQueitly:删除文件或文件夹且不会抛出异常
copyFile:复制文件
writeStringToFile:把字符写到目标文件,如果文件不存在,则创建
forceMkdir:强制创建文件夹,如果该文件夹父级目录不存在,则创建父级
write:把字符写到指定文件中
listFiles:列举某个目录下的文件(根据过滤器)
copyDirectory:复制文件夹
forceDelete:强制删除文件
2.3 org.apache.commons.io.FilenameUtils
getExtension:返回文件后缀名
getBaseName:返回文件名,不包含后缀名
getName:返回文件全名
concat:按命令行风格组合文件路径(详见方法注释)
removeExtension:删除后缀名
normalize:使路径正常化
wildcardMatch:匹配通配符
seperatorToUnix:路径分隔符改成unix系统格式的,即/
getFullPath:获取文件路径,不包括文件名
isExtension:检查文件后缀名是不是传入参数(List<String>)中的一个
2.4 org.springframework.util.FileCopyUtils
输入
从文件中读入到字节数组中
byte[] copyToByteArray(File in)
从输入流中读入到字节数组中
byte[] copyToByteArray(InputStream in)
从输入流中读入到字符串中
String copyToString(Reader in)
输出
从字节数组到文件
void copy(byte[] in, File out)
从文件到文件
int copy(File in, File out)
从字节数组到输出流
void copy(byte[] in, OutputStream out)
从输入流到输出流
int copy(InputStream in, OutputStream out)
从输入流到输出流
int copy(Reader in, Writer out)
从字符串到输出流
void copy(String in, Writer out)
2.5 org.springframework.util.ResourceUtils
从资源路径获取文件
判断字符串是否是一个合法的 URL 字符串。
static boolean isUrl(String resourceLocation)
获取 URL
static URL getURL(String resourceLocation)
获取文件(在 JAR 包内无法正常使用,需要是一个独立的文件)
static File getFile(String resourceLocation)
2.6 org.springframework.util.StreamUtils
输入
void copy(byte[] in, OutputStream out)
int copy(InputStream in, OutputStream out)
void copy(String in, Charset charset, OutputStream out)
long copyRange(InputStream in, OutputStream out, long start, long end)
输出
byte[] copyToByteArray(InputStream in)
String copyToString(InputStream in, Charset charset)
舍弃输入流中的内容
int drain(InputStream in)
3 字符串工具类
3.1 org.apache.commons.lang.StringUtils
isBlank:字符串是否为空 (trim后判断)
isEmpty:字符串是否为空 (不trim并判断)
equals:字符串是否相等
join:合并数组为单一字符串,可传分隔符
split:分割字符串
EMPTY:返回空字符串
trimToNull:trim后为空字符串则转换为null
replace:替换字符串
3.2 org.apache.commons.lang3.StringUtils
isBlank:字符串是否为空 (trim后判断)
isEmpty:字符串是否为空 (不trim并判断)
equals:字符串是否相等
join:合并数组为单一字符串,可传分隔符,例:StringUtils.join(list, ",")
split:分割字符串,StringUtils.split(str1,",")和str1.split(",")区别:使用StringUtils的split方法会返回null,而使用String的split方法会报指针异常
EMPTY:返回空字符串
replace:替换字符串
capitalize:首字符大写
StringUtils.isNumeric(str1);//判断是否纯数字
3.3 org.springframework.util.StringUtils
字符串判断工具
判断字符串是否为 null,或 ""。注意,包含空白符的字符串为非空
boolean isEmpty(Object str)
判断字符串是否是以指定内容结束。忽略大小写
boolean endsWithIgnoreCase(String str, String suffix)
判断字符串是否已指定内容开头。忽略大小写
boolean startsWithIgnoreCase(String str, String prefix)
是否包含空白符
boolean containsWhitespace(String str)
判断字符串非空且长度不为 0,即,Not Empty
boolean hasLength(CharSequence str)
判断字符串是否包含实际内容,即非仅包含空白符,也就是 Not Blank
boolean hasText(CharSequence str)
判断字符串指定索引处是否包含一个子串。
boolean substringMatch(CharSequence str, int index, CharSequence substring)
计算一个字符串中指定子串的出现次数
int countOccurrencesOf(String str, String sub)
字符串操作工具
查找并替换指定子串
String replace(String inString, String oldPattern, String newPattern)
去除尾部的特定字符
String trimTrailingCharacter(String str, char trailingCharacter)
去除头部的特定字符
String trimLeadingCharacter(String str, char leadingCharacter)
去除头部的空白符
String trimLeadingWhitespace(String str)
去除头部的空白符
String trimTrailingWhitespace(String str)
去除头部和尾部的空白符
String trimWhitespace(String str)
删除开头、结尾和中间的空白符
String trimAllWhitespace(String str)
删除指定子串
String delete(String inString, String pattern)
删除指定字符(可以是多个)
String deleteAny(String inString, String charsToDelete)
对数组的每一项执行 trim() 方法
String[] trimArrayElements(String[] array)
将 URL 字符串进行解码
String uriDecode(String source, Charset charset)
逗号分隔的String转换为数组
commaDelimitedStringToArray
把集合转为CSV格式字符串
collectionToDelimitedString
相当于split
delimitedListToStringArray
首字母小写
uncapitalize
把集合转为CSV格式字符串
collectionToDelimitedCommaString
和split基本一样,但能自动去掉空白的单词
tokenizeToStringArray
路径相关工具方法
解析路径字符串,优化其中的 “..”
String cleanPath(String path)
解析路径字符串,解析出文件名部分
String getFilename(String path)
解析路径字符串,解析出文件后缀名
String getFilenameExtension(String path)
比较两个两个字符串,判断是否是同一个路径。会自动处理路径中的 “..”
boolean pathEquals(String path1, String path2)
删除文件路径名中的后缀部分
String stripFilenameExtension(String path)
以 “. 作为分隔符,获取其最后一部分
String unqualify(String qualifiedName)
以指定字符作为分隔符,获取其最后一部分
String unqualify(String qualifiedName, char separator)
3.4 org.apache.commons.lang3.StringEscapeUtils(废弃)
unescapeHtml4:转义html
escapeHtml4:反转义html
escapeXml:转义xml
unescapeXml:反转义xml
escapeJava:转义unicode编码
escapeEcmaScript:转义EcmaScript字符
unescapeJava:反转义unicode编码
escapeJson:转义json字符
escapeXml10:转义Xml10
这个现在已经废弃了,建议使用commons-text包里面的方法。
4 对象属性及反射工具类
4.1 java.util.Objects
4.2 org.apache.http.util.EntityUtils
toString:把Entity转换为字符串
consume:确保Entity中的内容全部被消费。可以看到源码里又一次消费了Entity的内容,假如用户没有消费,那调用Entity时候将会把它消费掉
toByteArray:把Entity转换为字节流
consumeQuietly:和consume一样,但不抛异常
getContentCharset:获取内容的编码
4.3 org.apache.commons.beanutils.PropertyUtils
getProperty:获取对象属性值
setProperty:设置对象属性值
getPropertyDiscriptor:获取属性描述器
isReadable:检查属性是否可访问
copyProperties:复制属性值,从一个对象到另一个对象
getPropertyDiscriptors:获取所有属性描述器
isWriteable:检查属性是否可写
getPropertyType:获取对象属性类型
4.4 org.apache.commons.beanutils.BeanUtils
copyPeoperties:复制属性值,从一个对象到另一个对象
getProperty:获取对象属性值
setProperty:设置对象属性值
populate:根据Map给属性复制
copyPeoperty:复制单个值,从一个对象到另一个对象
cloneBean:克隆bean实例
4.5 org.springframework.beans.BeanUtils
BeanUtils.copyProperties(user1, user2);//拷贝对象的属性
BeanUtils.instantiateClass(User.class);//实例化某个类
BeanUtils.findDeclaredMethod(User.class, "getId");//获取指定类的指定方法
BeanUtils.findPropertyForMethod(declaredMethod);//获取指定方法的参数
使用例子:
Method declaredMethod = BeanUtils.findDeclaredMethod(User.class, "getId");
PropertyDescriptor propertyForMethod = BeanUtils.findPropertyForMethod(declaredMethod);
System.out.println(propertyForMethod.getName())
4.6 org.springframework.util.ClassUtils
ClassUtils.getAllInterfaces(new User());//获取对象的所有接口
ClassUtils.getPackageName(User.class);//获取某个类的包名
ClassUtils.isInnerClass(User.class);//判断某个类是否内部类
ClassUtils.isCglibProxy(new User());//判断对象是否代理对象
4.7 org.springframework.util.ReflectionUtils
获取方法
在类中查找指定方法
Method findMethod(Class<?> clazz, String name)
同上,额外提供方法参数类型作查找条件
Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes)
获得类中所有方法,包括继承而来的
Method[] getAllDeclaredMethods(Class<?> leafClass)
在类中查找指定构造方法
Constructor<T> accessibleConstructor(Class<T> clazz, Class<?>... parameterTypes)
是否是 equals() 方法
boolean isEqualsMethod(Method method)
是否是 hashCode() 方法
boolean isHashCodeMethod(Method method)
是否是 toString() 方法
boolean isToStringMethod(Method method)
是否是从 Object 类继承而来的方法
boolean isObjectMethod(Method method)
检查一个方法是否声明抛出指定异常
boolean declaresException(Method method, Class<?> exceptionType)
获取字段
在类中查找指定属性
Field findField(Class<?> clazz, String name)
同上,多提供了属性的类型
Field findField(Class<?> clazz, String name, Class<?> type)
是否为一个 "public static final" 属性
boolean isPublicStaticFinal(Field field)
设置字段
获取 target 对象的 field 属性值
Object getField(Field field, Object target)
设置 target 对象的 field 属性值,值为 value
void setField(Field field, Object target, Object value)
同类对象属性对等赋值
void shallowCopyFieldState(Object src, Object dest)
取消 Java 的权限控制检查。以便后续读写该私有属性
void makeAccessible(Field field)
对类的每个属性执行 callback
void doWithFields(Class<?> clazz, ReflectionUtils.FieldCallback fc)
同上,多了个属性过滤功能。
void doWithFields(Class<?> clazz, ReflectionUtils.FieldCallback fc,ReflectionUtils.FieldFilter ff)
同上,但不包括继承而来的属性
void doWithLocalFields(Class<?> clazz, ReflectionUtils.FieldCallback fc)
执行方法
执行方法
Object invokeMethod(Method method, Object target)
同上,提供方法参数
Object invokeMethod(Method method, Object target, Object... args)
取消 Java 权限检查。以便后续执行该私有方法
void makeAccessible(Method method)
取消 Java 权限检查。以便后续执行私有构造方法
void makeAccessible(Constructor<?> ctor)
4.8 org.springframework.util.ObjectUtils
获取对象的基本信息
获取对象的类名。参数为 null 时,返回字符串:"null"
String nullSafeClassName(Object obj)
参数为 null 时,返回 0
int nullSafeHashCode(Object object)
参数为 null 时,返回字符串:"null"
String nullSafeToString(boolean[] array)
获取对象 HashCode(十六进制形式字符串)。参数为 null 时,返回 0
String getIdentityHexString(Object obj)
获取对象的类名和 HashCode。参数为 null 时,返回字符串:""
String identityToString(Object obj)
相当于 toString()方法,但参数为 null 时,返回字符串:""
String getDisplayString(Object obj)
判断工具
判断数组是否为空
boolean isEmpty(Object[] array)
判断参数对象是否是数组
boolean isArray(Object obj)
判断数组中是否包含指定元素
boolean containsElement(Object[] array, Object element)
相等,或同为 null时,返回 true
boolean nullSafeEquals(Object o1, Object o2)
判断参数对象是否为空,判断标准为:
Optional: Optional.empty()
Array: length == 0
CharSequence: length == 0
Collection: Collection.isEmpty()
Map: Map.isEmpty()
boolean isEmpty(Object obj)
其他工具方法
向参数数组的末尾追加新元素,并返回一个新数组
<A, O extends A> A[] addObjectToArray(A[] array, O obj)
原生基础类型数组 --> 包装类数组
Object[] toObjectArray(Object source)
4.9 org.springframework.util.AopUtils
判断代理类型
判断是不是 Spring 代理对象
boolean isAopProxy()
判断是不是 jdk 动态代理对象
isJdkDynamicProxy()
判断是不是 CGLIB 代理对象
boolean isCglibProxy()
获取被代理对象的 class
获取被代理的目标 class
Class<?> getTargetClass()
4.10 org.springframework.util.AopContext
获取当前对象的代理对象
获取当前对象的代理对象
Object currentProxy()
5 网络序列化工具类
5.1 org.apache.http.client.utils.URLEncodedUtils
format:格式化参数,返回一个HTTP POST或者HTTP PUT可用application/x-www-form-urlencoded字符串
parse:把String或者URI等转换为List<NameValuePair>
5.2 org.apache.http.HttpStatus
把常用的http返回码给我们定义好了,直接拿来用就可以了,真的不用再重复定义了(org.springframework.http.HttpStatus也是同样的)
5.3 org.springframework.util.SerializationUtils
有时候,我们需要把数据进行**序列化
和反序列化
处理。传统的做法是某个类实现Serializable
接口,然后重新它的writeObject
和readObject
**方法。但如果使用org.springframework.util
包下的SerializationUtils
工具类,能更轻松实现序列化和反序列化功能。
Map<String, String> map = Maps.newHashMap();
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
byte[] serialize = SerializationUtils.serialize(map);
Object deserialize = SerializationUtils.deserialize(serialize);
System.out.println(deserialize);
6 加解密工具类
6.1 org.apache.commons.codec.digest.DigestUtils
md5Hex:MD5加密,返回32位字符串,例:DigestUtils.md5Hex("技术");
sha1Hex:SHA-1加密
sha256Hex:SHA-256加密,例:DigestUtils.sha256Hex("技术");
sha512Hex:SHA-512加密
md5:MD5加密,返回16位字符串
6.2 org.springframework.util.Base64Utils
有时候,为了安全考虑,需要将参数只用**base64
**编码。这时就能直接使用org.springframework.util
包下的Base64Utils
工具类。
它里面包含:encode
和decode
方法,用于对数据进行加密和解密。例如
String str = "abc";
String encode = new String(Base64Utils.encode(str.getBytes()));
System.out.println("加密后:" + encode);
try {
String decode = new String(Base64Utils.decode(encode.getBytes()), "utf8");
System.out.println("解密后:" + decode);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
6.3 java.nio.charset.StandardCharsets
我们在做字符转换的时候,经常需要指定字符编码,比如:UTF-8、ISO-8859-1等等。这时就可以直接使用java.nio.charset
包下的StandardCharsets
类中静态变量。
例如:
String str = "abc";
String encode = new String(Base64Utils.encode(str.getBytes()));
System.out.println("加密后:" + encode);
String decode = new String(Base64Utils.decode(encode.getBytes()), StandardCharsets.UTF_8);
System.out.println("解密后:" + decode);
7 其他工具类
7.1 org.apache.commons.lang3.BooleanUtils
BooleanUtils.isTrue(aBoolean);//判断true
BooleanUtils.isFalse(aBoolean);//判断false
BooleanUtils.isNotTrue(aBoolean);//判断不为true
BooleanUtils.isNotFalse(aBoolean);//判断不为false
BooleanUtils.toInteger(aBoolean);//转换成数字,将true转换成数字1,false转换成数字0
BooleanUtils.toBoolean(aBoolean);//Boolean转换成布尔值,将包装类Boolean对象,转换成原始的boolean对象,可以使用toBoolean方法
7.2 org.springframework.util.Assert
7.2.1 断言参数是否为空
String str = null;
Assert.isNull(str, "str必须为空");
Assert.isNull(str, () -> "str必须为空");
Assert.notNull(str, "str不能为空");
如果不满足条件就会抛出IllegalArgumentException
异常
7.2.2 断言集合是否为空
断言集合
是否空,如果不满足条件,则直接抛异常,如果不满足条件就会抛出IllegalArgumentException
异常
List<String> list = null;
Map<String, String> map = null;
Assert.notEmpty(list, "list不能为空");
Assert.notEmpty(list, () -> "list不能为空");
Assert.notEmpty(map, "map不能为空");
7.2.3 断言条件是否为空
断言是否满足某个条件
,如果不满足条件,则直接抛异常。
List<String> list = null;
Assert.isTrue(CollectionUtils.isNotEmpty(list), "list不能为空");
Assert.isTrue(CollectionUtils.isNotEmpty(list), () -> "list不能为空");
7.3 org.slf4j.MDC
MDC
是org.slf4j
包下的一个类,它的全称是Mapped Diagnostic Context,我们可以认为它是一个线程安全的存放诊断日志的容器。
MDC的底层是用了**ThreadLocal
**来保存数据的。我们可以用它传递参数。
例如现在有这样一种场景:我们使用**RestTemplate
**调用远程接口时,有时需要在header
中传递信息,比如:traceId,source等,便于在查询日志时能够串联一次完整的请求链路,快速定位问题。这种业务场景就能通过ClientHttpRequestInterceptor
接口实现,具体做法如下
第一步,定义一个LogFilter拦截所有接口请求,在MDC中设置traceId:
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
MdcUtil.add(UUID.randomUUID().toString());
System.out.println("记录请求日志");
chain.doFilter(request, response);
System.out.println("记录响应日志");
}
@Override
public void destroy() {
}
}
第二步,实现**ClientHttpRequestInterceptor
**接口,MDC中获取当前请求的traceId,然后设置到header中
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().set("traceId", MdcUtil.get());
return execution.execute(request, body);
}
}
第三步,定义配置类,配置上面定义的RestTemplateInterceptor
类:
@Configuration
public class RestTemplateConfiguration {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors
(Collections.singletonList(restTemplateInterceptor()));
return restTemplate;
}
@Bean
public RestTemplateInterceptor restTemplateInterceptor() {
return new RestTemplateInterceptor();
}
}
其中MdcUtil其实是利用MDC工具在ThreadLocal中存储和获取traceId
public class MdcUtil {
private static final String TRACE_ID = "TRACE_ID";
public static String get() {
return MDC.get(TRACE_ID);
}
public static void add(String value) {
MDC.put(TRACE_ID, value);
}
}
能使用MDC保存traceId等参数的根本原因是,用户请求到应用服务器,Tomcat会从线程池中分配一个线程去处理该请求。那么该请求的整个过程中,保存到MDC的ThreadLocal中的参数,也是该线程独享的,所以不会有线程安全问题