领先一步
VMware 提供培训和认证,以快速提升您的进步。
了解更多欢迎来到《你可能不需要另一个库》(YMNNALFT) 的另一个环节!自从2016年以来,我在我的Spring Tips 视频中花费了大量时间阐明(或者至少尝试阐明!)Spring 生态系统中一些更巨大的机遇。然而,今天我以不同的精神来到这里,想关注那些功能强大的、有时隐藏的小巧宝石,它们可以为你节省额外的第三方依赖及其隐含的复杂性。
我们都经历过这种情况。你想要一些日常的字符串操作例程,所以你把它提取到一个单独的抽象类中,并将其公开为一个static
方法。然后,有一些用于构建java.util.Collection<T>
的工厂方法,所以你把它提取到一个单独的类中,并将其公开为一个static
方法。最终,你将在你的代码库中收集所有这些东西,并且它们之间几乎没有内聚性。毕竟,这并没有那么多,对吧?这些本质上只是全局函数,而不是真正有状态对象的方法
。
这并不是说构建你自己的静态方法本身就是错误的,只要你遵循一些约定。例如,我们通常使用带有静态方法的抽象类。
这一切开始得如此不起眼。当然,确实如此。你知道这个循环。首先,在公司范围内的构件库中的 jar 文件中,一个单独的类中包含一些方法。然后是类,复数。现在包
已经出现了。包很麻烦!你将开始意识到最好考虑一下组织结构,否则事情很快就会失控。你开始接受拉取请求。在某些时候,会出现重大更改,并且手持干草叉的开发人员会排在你家门口。你不知道为什么每个人都总是要在工作时划破你的轮胎。太夸张了!所以你让公司开源你新生的模块。现在是整个世界
的问题了!就像电子宠物和真人秀一样,没有尽头。而那个广阔的世界?好吧,那个广阔的世界非常喜欢在点版本中进行重大更改,他们会因为这些更改而爱你
!
也许吧。
还有另一种方法。
有许多质量参差不齐的第三方实用程序库: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
- 用于处理 JavaBean 的实用函数ClassUtils
- 用于以反射方式询问类型信息的实用函数SystemPropertyUtils
- 用于处理System
属性的实用函数FileCopyUtils
- 用于复制InputStream
和OutputStream
实现的实用函数AopUtils
- 用于处理 Spring 的 AOP 代理的实用函数ReflectionUtils
- 用于广泛处理反射的实用函数Assert
- 有助于进行基于契约设计的断言的实用函数CollectionUtils
- 用于处理各种 Javajava.util.Collection
类型的实用函数SerializeUtils
- 用于处理 Java 序列化的实用函数有很多令人兴奋的内容,而这个密集的示例甚至没有触及表面!
你喜欢这种一目了然的方法吗?你学到了什么吗?一如既往,我很想知道你的想法,所以请在 Twitter (@starbuxman) 上发表你的看法!我将继续撰写《YMNNALFT》的另一个部分,所以请不要错过。