領先一步
VMware 提供培訓和認證,以加速您的進度。
了解更多歡迎來到您可能不需要另一個程式庫 (YMNNALFT) 的另一個專欄!自 2016 年以來,我花了很多時間在 我的 Spring Tips 影片中,闡明(或試圖闡明!)Spring 生態系統中一些更龐大的機會。然而,今天,我以不同的精神來到您面前,希望專注於那些做很棒事情的小而隱藏的瑰寶,它們可能會讓您免於額外的第三方依賴及其隱含的複雜性。
我們都經歷過。您想要一些日常的字串操作例程,因此您將其提取到一個單獨的抽象類別中,並將其公開為 static
方法。然後,有一個用於構建 java.util.Collection<T>
的工廠方法,因此您將其提取到一個單獨的類別中,並將其公開為 static
方法。最終,您會在程式碼庫中散布這些東西的集合,並且它們之間幾乎沒有凝聚力。畢竟,沒有太多內容,對吧?這些本質上只是全域函數,而不是有狀態物件上的方法本身。
並不是說建立自己的靜態方法本質上是錯誤的,只要您以某些約定來處理它們即可。例如,我們通常使用帶有靜態方法的抽象類別。
一切都始於如此無害。當然,確實如此。您知道這個週期。首先,一些方法位於公司範圍內 artifact 儲存庫的 jar 中的一個孤立類別中。然後有複數形式的類別。現在套件已經進入畫面。套件很麻煩!您將開始意識到最好對組織進行一些思考,否則事情會很快失控。您開始接受 pull request。在某個時候,會發生重大變更,開發人員會帶著乾草叉在您門外排隊。您想知道為什麼每個人都一直吃東西並在工作中劃破您的輪胎。太過分了!因此,您讓公司對您新生的模組進行開源。現在是世界的問題了!就像電子雞和真人實境節目一樣,沒有盡頭。而那個廣闊的世界?嗯,那個廣闊的世界喜歡在點發佈版本中進行重大變更,並且他們會因為這些變更而愛你!
也許吧。
還有另一種方法。
市面上有許多品質不一的第三方實用程式庫:GS Collections、Apache Commons、Guava 等。這裡不乏選擇。您是否知道 Spring 在框架本身中提供了幾個實用類別,可能會讓您免於依賴?我並不是說它們會做您可能從傑出競爭對手那裡獲得的一切,但您可能會感到驚訝!此範例將研究其中的一些實用類別,但在類別路徑上還有許多其他類別。您通常可以透過進入 IDE 並在類別搜尋中搜尋 *Utils
或在檔案搜尋中搜尋 *Utils.java
來找到它們。讓我們看看其中的一些。
org.springframework.boot
: spring-boot-starter
這是程式碼
package bootiful.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jmx.support.JmxUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.*;
import javax.annotation.PostConstruct;
import java.beans.PropertyDescriptor;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;
@Log4j2
@SpringBootApplication
public class BootifulApplication {
@Data
@AllArgsConstructor
@Component
public static class DemoClass {
@PostConstruct
public void begin() {
log.info("begin()");
}
private final List<Map<String, Object>> list = new ArrayList<>();
}
@Bean
ApplicationListener<ApplicationReadyEvent> ready(DemoClass demo) {
return event -> {
Assert.notNull(demo.getList(), "the list can't be null");
beansUtils(demo);
classUtils();
systemPropertyUtils();
fileCopyUtils();
aop(demo);
reflection();
ensure();
collections();
serialize();
};
}
private void ensure() {
int counter = 2;
Assert.state(counter == 2, () -> "the counter should be 2 or more. Was " + counter);
Assert.hasText("Hello, world!", () -> "this string should be a non-null, non-empty String");
}
private void reflection() {
ReflectionUtils.doWithFields(DemoClass.class, field -> log.info("field = " + field.toString()));
ReflectionUtils.doWithMethods(DemoClass.class, method -> log.info("method = " + method.toString()));
Field list = ReflectionUtils.findField(DemoClass.class, "list");
log.info(Objects.requireNonNull(list).toString());
ResolvableType rt = ResolvableType.forField(list);
log.info(rt.toString());
}
private void aop(DemoClass demoClass) {
Class<?> targetClass = AopUtils.getTargetClass(demoClass);
log.info("Class<?> is " + targetClass);
log.info("is AOP proxy? " + AopUtils.isAopProxy(demoClass));
log.info("is CGlib proxy? " + AopUtils.isCglibProxy(demoClass));
}
private void collections() {
Collection<String> names = Arrays.asList("Tammie", "Kimly", "Josh");
boolean contains = CollectionUtils.containsAny(names, Arrays.asList("Josh"));
Assert.state(contains, () -> "one or more of the names in " + names.toString() + " should be present");
}
private void serialize() {
Customer in = new Customer(593232329, "Josh");
byte[] bytes = SerializationUtils.serialize(in);
Customer out = (Customer) SerializationUtils.deserialize(bytes);
Assert.state(out.getId() == in.getId() && out.getName().equals(in.getName()),
() -> "the " + Customer.class.getName() + " did not serialize correctlyy");
}
private void fileCopyUtils() {
Resource cpr = new ClassPathResource("/application.properties");
try (Reader r = new InputStreamReader(cpr.getInputStream())) {
String contents = FileCopyUtils.copyToString(r);
log.info("application.properties contents: " + contents);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private void systemPropertyUtils() {
String resolvedText = SystemPropertyUtils.resolvePlaceholders("my home directory is ${user.home}");
log.info("resolved text: " + resolvedText);
}
private void classUtils() {
Constructor<DemoClass> demoClassConstructor = ClassUtils.getConstructorIfAvailable(DemoClass.class);
log.info("demoClassConstructor: " + demoClassConstructor);
try {
DemoClass demoClass = demoClassConstructor.newInstance();
log.info("newInstance'd demoClass: " + demoClass);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private void beansUtils(DemoClass demo) {
PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(demo.getClass());
for (PropertyDescriptor pd : descriptors) {
log.info("pd: " + pd.getName());
}
}
public static void main(String[] args) {
SpringApplication.run(BootifulApplication.class, args);
}
}
@Data
class Customer implements Serializable {
static final long serialVersionUID = 1L;
private int id;
private String name;
public Customer(int id, String name) {
this.id = id;
this.name = name;
}
}
此範例介紹了 Spring 生態系統中各種 Utils
類別實作的自助餐。它著眼於
BeanUtils
- 用於處理 JavaBeans 的有用函數ClassUtils
- 用於以反射方式詢問類型問題的有用函數SystemPropertyUtils
- 用於處理 System
屬性的有用函數FileCopyUtils
- 用於複製 InputStream
和 OutputStream
實作的有用函數AopUtils
- 用於處理 Spring 的 AOP 代理的有用函數ReflectionUtils
- 用於廣泛處理反射的有用函數Assert
- 有助於設計合約樣式斷言的有用函數CollectionUtils
- 用於處理各種 Java java.util.Collection
類型的有用函數SerializeUtils
- 用於處理 Java 序列化的有用函數有很多令人興奮的東西,這個密集的範例甚至沒有開始觸及表面!
您喜歡這種一目了然的方法嗎?您學到什麼了嗎?一如既往,我很想收到您的來信,所以請在 Twitter 上發聲 (@starbuxman) !我將會帶著另一個YMNNALFT專欄回來,所以一定要錯過!