YMNNALFT:Spring 的实用工具类

工程 | 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.bootspring-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 - 用于复制InputStreamOutputStream实现的实用函数
  • AopUtils - 用于处理 Spring 的 AOP 代理的实用函数
  • ReflectionUtils - 用于广泛处理反射的实用函数
  • Assert - 有助于进行基于契约设计的断言的实用函数
  • CollectionUtils - 用于处理各种 Javajava.util.Collection类型的实用函数
  • SerializeUtils - 用于处理 Java 序列化的实用函数

有很多令人兴奋的内容,而这个密集的示例甚至没有触及表面!

你喜欢这种一目了然的方法吗?你学到了什么吗?一如既往,我很想知道你的想法,所以请在 Twitter (@starbuxman) 上发表你的看法!我将继续撰写《YMNNALFT》的另一个部分,所以请不要错过。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以快速提升您的进步。

了解更多

获得支持

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

了解更多

即将举行的活动

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

查看全部