Spring 自帶工具類使用學習
theme: vuepress highlight: atom-one-dark
我們專案大多數都是基於Spring架構,Spring自身包含了許多實用的工具類,學習這些工具類的使用不僅能讓我們達到事半功倍的效果,而且還能減少不必要的額外的工具類的引入。檢視這些工具類的原始碼時發現它們都是abstract型別的,這是因為工具類的方法一般都是static靜態方法,靜態方法和類繫結,類載入後就能使用了,無需例項化(剛好abstract類不能直接例項化,並且可以定義非抽象方法),所以工具類定義為abstract型別再合適不過。
本文print方法為System.out.println的封裝:
java
private static void print(Object value) {
System.out.println(value);
}
ClassUtils
org.springframework.util.classUtils
包含一些和java.lang.Class
相關的實用方法。
getDefaultClassLoader
ClassLoader getDefaultClassLoader()
獲取當前執行緒上下文的類載入器:
java
print(ClassUtils.getDefaultClassLoader());
java
sun.misc.Launcher$AppClassLoader@18b4aac2
overrideThreadContextClassLoader
ClassLoader overrideThreadContextClassLoader(@Nullable ClassLoader classLoaderToUse)
用特定的類載入器覆蓋當前執行緒上下文的類載入器:
java
print(ClassUtils.getDefaultClassLoader());
ClassUtils.overrideThreadContextClassLoader(ClassLoader.getSystemClassLoader().getParent());
print(ClassUtils.getDefaultClassLoader());
java
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@3feba861
forName
forName(String name, @Nullable ClassLoader classLoader)
通過類名返回類例項,類似於Class.forName(),但功能更強,可以用於原始型別,內部類等:
java
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
print(ClassUtils.forName("int", classLoader));
print(ClassUtils.forName("java.lang.String[]", classLoader));
print(ClassUtils.forName("java.lang.Thread$State", classLoader));
java
int
class [Ljava.lang.String;
class java.lang.Thread$State
isPresent
boolean isPresent(String className, @Nullable ClassLoader classLoader)
判斷當前classLoader是否包含目標型別(包括它的所有父類和介面):
java
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
print(ClassUtils.isPresent("int", classLoader));
print(ClassUtils.isPresent("intt", classLoader));
true
false
resolvePrimitiveClassName
Class<?> resolvePrimitiveClassName(@Nullable String name)
通過給定類名獲取原始類:
java
print(ClassUtils.resolvePrimitiveClassName("int"));
print(ClassUtils.resolvePrimitiveClassName("java.lang.Integer"));
int
null
isPrimitiveWrapper
boolean isPrimitiveWrapper(Class<?> clazz)
判斷給定類是否為包裝類,如Boolean, Byte, Character, Short, Integer, Long, Float, Double 或者 Void:
java
print(ClassUtils.isPrimitiveWrapper(Integer.class));
print(ClassUtils.isPrimitiveWrapper(Character.class));
print(ClassUtils.isPrimitiveWrapper(Void.class));
print(ClassUtils.isPrimitiveWrapper(String.class));
true
true
true
false
類似的方法還有isPrimitiveOrWrapper
判斷是否為原始類或者包裝類、isPrimitiveWrapperArray
判斷是否為包裝類陣列、isPrimitiveArray
判斷是否為原始類陣列。
resolvePrimitiveIfNecessary
Class<?> resolvePrimitiveIfNecessary(Class<?> clazz)
如果給定類是原始類,則返回對應包裝類,否則直接返回給定類:
java
print(ClassUtils.resolvePrimitiveIfNecessary(int.class));
print(ClassUtils.resolvePrimitiveIfNecessary(Object.class));
java
class java.lang.Integer
class java.lang.Object
isAssignable
boolean isAssignable(Class<?> lhsType, Class<?> rhsType)
通過反射檢查,是否可以將rhsType賦值給lhsType(注意,包裝型別可以賦值給相應的原始型別,自動拆裝箱機制):
java
print(ClassUtils.isAssignable(Integer.class, int.class));
print(ClassUtils.isAssignable(Object.class, String.class));
print(ClassUtils.isAssignable(BeanPostProcessor.class, InstantiationAwareBeanPostProcessor.class));
print(ClassUtils.isAssignable(double.class, Double.class)); // consider this
print(ClassUtils.isAssignable(Integer.class, Long.class));
java
true
true
true
true
false
isAssignableValue
boolean isAssignableValue(Class<?> type, @Nullable Object value)
判斷給定的值是否符合給定的型別:
java
print(ClassUtils.isAssignableValue(Integer.class, 1));
print(ClassUtils.isAssignableValue(Integer.class, 1L));
print(ClassUtils.isAssignableValue(int.class, Integer.valueOf(1)));
print(ClassUtils.isAssignableValue(Object.class,1));
print(ClassUtils.isAssignableValue(String.class,1));
true
false
true
true
false
convertResourcePathToClassName
String convertResourcePathToClassName(String resourcePath)
將類路徑轉換為全限定類名:
java
print(ClassUtils.convertResourcePathToClassName("java/lang/String"));
java
java.lang.String
實際上就是將/
替換為.
。convertClassNameToResourcePath
方法功能相反。
classNamesToString
String classNamesToString(Class<?>... classes)
直接看演示不解釋:
java
print(ClassUtils.classNamesToString(String.class, Integer.class, BeanPostProcessor.class));
java
[java.lang.String, java.lang.Integer, org.springframework.beans.factory.config.BeanPostProcessor]
getAllInterfaces
Class<?>[] getAllInterfaces(Object instance)
返回給定例項物件所實現介面型別集合:
java
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
Class<?>[] allInterfaces = ClassUtils.getAllInterfaces(processor);
Arrays.stream(allInterfaces).forEach(System.out::println);
java
interface org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor
interface org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor
interface org.springframework.core.PriorityOrdered
interface org.springframework.beans.factory.BeanFactoryAware
類似的方法還有getAllInterfacesForClass
、getAllInterfacesAsSet
、getAllInterfacesForClassAsSet
determineCommonAncestor
Class<?> determineCommonAncestor(@Nullable Class<?> clazz1, @Nullable Class<?> clazz2)
尋找給定型別的共同祖先(所謂共同祖先指的是給定型別呼叫class.getSuperclass
獲得的共同型別,如果給定型別是Object.class,介面,原始型別或者Void,直接返回null):
java
// 它兩都是介面
print(ClassUtils.determineCommonAncestor(AutowireCapableBeanFactory.class, ListableBeanFactory.class));
print(ClassUtils.determineCommonAncestor(Long.class, Integer.class));
print(ClassUtils.determineCommonAncestor(String.class, Integer.class));
null
class java.lang.Number
null
isInnerClass
boolean isInnerClass(Class<?> clazz)
判斷給定型別是否為內部類(非靜態):
```java class A { class B {
}
} print(ClassUtils.isInnerClass(A.B.class)); // true ```
```java static class A { class B {
}
} print(ClassUtils.isInnerClass(A.B.class)); // true static class A { static class B {
}
} print(ClassUtils.isInnerClass(A.B.class)); // false ```
isCglibProxy
boolean isCglibProxy(Object object)
是否為Cglib代理物件:
```java @SpringBootApplication public class AopApplication {
@Configuration
static class MyConfigure {
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AopApplication.class, args);
MyConfigure myConfigure = context.getBean(MyConfigure.class);
System.out.println(ClassUtils.isCglibProxy(myConfigure));
}
} ```
true
配置類不由Cglib代理的話,返回為false:
```java @SpringBootApplication public class AopApplication {
@Configuration(proxyBeanMethods = false) // 注意這裡
static class MyConfigure {
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AopApplication.class, args);
MyConfigure myConfigure = context.getBean(MyConfigure.class);
System.out.println(ClassUtils.isCglibProxy(myConfigure));
}
} ```
false
不過這個方法廢棄了,建議使用org.springframework.aop.support.AopUtils.isCglibProxy(Object)
方法。
getUserClass
Class<?> getUserClass(Object instance)
返回給定例項對應的型別,如果例項是Cglib代理後的物件,則返回代理的目標物件型別:
java
print(ClassUtils.getUserClass("Hello")); // class java.lang.String
Cglib代理例子:
```java @SpringBootApplication public class AopApplication {
@Configuration
static class MyConfigure {
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AopApplication.class, args);
MyConfigure myConfigure = context.getBean(MyConfigure.class);
// 注意它們的區別
System.out.println(myConfigure.getClass());
System.out.println(ClassUtils.getUserClass(myConfigure));
}
} ```
java
class cc.mrbird.aop.AopApplication$MyConfigure$$EnhancerBySpringCGLIB$$e51ce45
class cc.mrbird.aop.AopApplication$MyConfigure
matchesTypeName
boolean matchesTypeName(Class<?> clazz, @Nullable String typeName)
判斷給定class和型別名稱是否匹配:
java
print(ClassUtils.matchesTypeName(String.class, "java.lang.String")); // true
getShortName
String getShortName(Class<?> clazz)
返回類名:
java
print(ClassUtils.getShortName(String.class)); // String
getShortNameAsProperty
String getShortNameAsProperty(Class<?> clazz)
返回首字母小寫的類名,如果是內部類的話,則去掉外部類名:
java
print(ClassUtils.getShortNameAsProperty(String.class)); // string
java
class A {
class B {
}
}
print(ClassUtils.getShortNameAsProperty(String.class)); // b
getClassFileName
String getClassFileName(Class<?> clazz)
返回類名+.class:
java
print(ClassUtils.getShortNameAsProperty(String.class)); // String.class
getPackageName
String getPackageName(Class<?> clazz)
返回包名:
java
print(ClassUtils.getShortNameAsProperty(String.class)); // java.lang
getQualifiedName
String getQualifiedName(Class<?> clazz)
返回全限定類名,如果是陣列型別則末尾加[]:
java
print(ClassUtils.getQualifiedName(String.class));
print(ClassUtils.getQualifiedName(String[].class));
java
java.lang.String
java.lang.String[]
getQualifiedMethodName
String getQualifiedMethodName(Method method)
獲取方法的全限定名:
java
print(ClassUtils.getQualifiedMethodName(
ClassUtils.class.getDeclaredMethod("getQualifiedMethodName", Method.class
)));
java
org.springframework.util.ClassUtils.getQualifiedMethodName
hasConstructor
boolean hasConstructor(Class<?> clazz, Class<?>... paramTypes)
判斷給定型別是否有給定型別引數構造器:
java
print(ClassUtils.hasConstructor(String.class, String.class));
print(ClassUtils.hasConstructor(String.class, Object.class));
true
false
getConstructorIfAvailable
<T> Constructor<T> getConstructorIfAvailable(Class<T> clazz, Class<?>... paramTypes)
返回給定型別的給定引數型別構造器,沒有的話返回null:
java
Constructor<String> constructorIfAvailable = ClassUtils.getConstructorIfAvailable(String.class, String.class);
print(constructorIfAvailable != null);
print(constructorIfAvailable.toString());
java
true
public java.lang.String(java.lang.String)
hasMethod
boolean hasMethod(Class<?> clazz, Method method)
判斷給定型別是否有指定的方法:
java
Method hasMethod = ClassUtils.class.getDeclaredMethod("hasMethod", Class.class, Method.class);
print(ClassUtils.hasMethod(ClassUtils.class, hasMethod)); // true
過載方法boolean hasMethod(Class<?> clazz, String methodName, Class<?>... paramTypes)
。
getMethod
Method getMethod(Class<?> clazz, String methodName, @Nullable Class<?>... paramTypes)
從指定型別中找指定方法,沒找到拋IllegalStateException異常:
java
ClassUtils.getMethod(ClassUtils.class,"hello", String.class);
java
java.lang.IllegalStateException: Expected method not found: java.lang.NoSuchMethodException: org.springframework.util.ClassUtils.hello(java.lang.String)
如果希望沒找到返回null,而非拋異常,可以用getMethodIfAvailable
方法。
getMethodCountForName
int getMethodCountForName(Class<?> clazz, String methodName)
從指定型別中通過方法名稱查詢該方法個數(重寫、過載、非public的都算):
java
print(ClassUtils.getMethodCountForName(ClassUtils.class,"hasMethod")); // 2
類似的方法還有hasAtLeastOneMethodWithName
,至少得有一個。
getStaticMethod
Method getStaticMethod(Class<?> clazz, String methodName, Class<?>... args)
獲取給定型別的靜態方法,如果該方法不是靜態的或者沒有這個方法,則返回null:
java
Method method = ClassUtils.getStaticMethod(ClassUtils.class, "getDefaultClassLoader");
print(method != null);
print(method.getReturnType());
java
true
class java.lang.ClassLoader
FileSystemUtils
檔案系統實用工具類
deleteRecursively
boolean deleteRecursively(@Nullable File root)
遞迴刪除指定檔案或目錄,刪除成功返回true,失敗返回false,不會丟擲異常。
實用File的delete目錄嘗試刪除a目錄:
java
File file = new File("a");
print(file.delete()); // false
因為a目錄包含子目錄(檔案),所以應該使用遞迴刪除:
java
File file = new File("a");
print(FileSystemUtils.deleteRecursively(file)); // true
過載方法boolean deleteRecursively(@Nullable Path root)
和該方法功能相似,但該方法可能會丟擲IO異常。
copyRecursively
void copyRecursively(File src, File dest)
遞迴複製src檔案到dest(目標路徑不存在則自動建立):
java
File src = new File("a");
File dest = new File("aa");
FileSystemUtils.copyRecursively(src, dest);
過載方法void copyRecursively(Path src, Path dest)
。
StreamUtils
包含一些檔案流的實用方法預設的緩衝區大小為4096bytes。
注意:該工具類的所有方法都不會對流進行關閉處理!