YMNNALFT: Spring *Utils 类

工程 | Josh Long | 2021 年 1 月 27 日 | ...

欢迎来到又一期的 *你可能不需要另一个库来实现它* (YMNNALFT)! 自 2016 年以来,我花了很多时间在 我的 Spring Tips 视频中阐明(或者试图阐明!)Spring 生态系统中一些更大的机会。然而,今天,我以不同的精神来到你面前,希望专注于那些小而有时隐藏的宝石,它们可以完成出色的工作,并且可能会让你免于额外的第三方依赖及其隐含的复杂性。

我们都遇到过这种情况。你想要一些日常的字符串操作例程,所以你将其提取到一个单独的抽象类中,并将其公开为一个 static 方法。然后,有一些工厂方法用于构建 java.util.Collection<T>,因此你将其提取到一个单独的类中,并将其公开为一个 static 方法。最终,你在代码库中散布着这些东西的集合,它们之间几乎没有凝聚力。毕竟,没有什么太多可说的,对吧? 这些本质上只是全局函数,而不是有状态对象上的真正方法,本身

并不是说构建你自己的静态方法本质上是错误的,只要你以一些约定来对待它们。 例如,我们通常使用带有静态方法的抽象类。

这一切都始于如此无害。 当然,事实确实如此。 你知道这个周期。 首先,是一个孤立类中的一些方法,被困在一个公司范围内的工件存储库中的 jar 中。 然后有类,复数。 现在已经进入视野。 包是麻烦! 你将开始意识到最好对组织进行一些思考,否则事情会很快失控。 你开始接受拉取请求。 在某些时候,会出现重大更改,并且手持干草叉的开发人员会在你的门口排队。 你想知道为什么每个人都一直在上班时削减你的轮胎。 太多了! 所以你让公司开源你正在起步的模块。 现在是世界的问题! 就像电子宠物和真人秀一样,没有尽头。 那个广阔的世界? 好吧,那个广阔的世界喜欢在点发布中进行重大更改,并且他们会爱你的!

也许吧。

还有另一种方法。

市面上有很多质量参差不齐的第三方实用程序库:GS Collections、Apache Commons、Guava 等。这里不乏选择。你知道 Spring 本身在框架中提供了几个实用程序类,可能会让你免于依赖吗? 我并不是说它们会完成你可以从杰出竞争对手那里获得的一切,但你可能会感到惊讶! 此示例将查看其中的一些实用程序类,但在类路径上还有许多其他实用程序类。 你通常可以通过进入你的 IDE 并在类搜索中搜索 *Utils 或在文件搜索中搜索 *Utils.java 来找到它们。 让我们来看一些。

  • 通过以下对 Spring Initializr 的传递(或默认)依赖,每个 Spring Boot 项目中默认都包含许多这些实用程序类 - 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 - 用于复制 InputStreamOutputStream 实现的有用函数
  • AopUtils - 用于处理 Spring 的 AOP 代理的有用函数
  • ReflectionUtils - 用于广泛处理反射的有用函数
  • Assert - 用于帮助设计合同样式断言的有用函数
  • CollectionUtils - 用于处理各种 Java java.util.Collection 类型的有用函数
  • SerializeUtils - 用于处理 Java 序列化的有用函数

这里有大量令人兴奋的东西,即使这个密集的例子甚至没有开始触及表面!

你喜欢这种一览无遗的宝石方法吗? 你学到了什么吗? 与往常一样,我渴望收到你的来信,所以 请在 Twitter 上发声 (@starbuxman) ! 我会带着另一期 YMNNALFT 回来,所以请务必不要错过。

获取 Spring 新闻通讯

与 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速你的进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中为 OpenJDK™、Spring 和 Apache Tomcat® 提供支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部