【小家Spring】Spring Framework提供的实用纯Java工具类大合集(一)(上)

简介: 【小家Spring】Spring Framework提供的实用纯Java工具类大合集(一)(上)

前言

在Spring Framework里的spring-core核心包里面,有个org.springframework.util里面有不少非常实用的工具类。


该工具包里面的工具类虽然是被定义在Spring下面的,但是由于Spring框架目前几乎成了JavaEE实际的标准了,因此我们直接使用也是无妨的,很多时候能够大大的提高我们的生产力。本文主要介绍一些个人认为还非常实用的工具类,仅仅代表个人意见哦~


image.png


此处提到的工具类为纯工具类。与Spring的Bean没有关系,是最为共用的工具类


IdGenerator 唯一键生成器 UUID


UUID除了生成的字符串比较长以外,几乎没有缺点(当然用字符串做主键,也算一个小缺点吧)


Spring给我提供了接口:IdGenerator 来生成id代表唯一箭,它内置提供了三个实现:


image.png


JdkIdGenerator


JDK的工具类包util包中就为我们提供了一个很好的工具类,即UUID。UUID(Universally Unique Identifier)通用唯一识别码。

  @Override
  public UUID generateId() {
    return UUID.randomUUID();
  }


底层字节调用JDK的UUID方法,因此不做过多介绍了


AlternativeJdkIdGenerator


这是Spring提供给我们的重头戏,用它来取代JDK的UUID的生成。从它的javadoc说明:


 * An {@link IdGenerator} that uses {@link SecureRandom} for the initial seed and
 * {@link Random} thereafter, instead of calling {@link UUID#randomUUID()} every
 * time as {@link org.springframework.util.JdkIdGenerator JdkIdGenerator} does.
 * This provides a better balance between securely random ids and performance.

大意是:它使用了SecureRandom作为种子,来替换调用UUID#randomUUID()。它提供了一个更好、更高性能的表现(关于性能比较,下面会给出一个例子)


SimpleIdGenerator


类似于自增的Id生成器。每调用一次,自增1(一般比较少使用 指导就行了)


三者性能比较:


    public static void main(String[] args) {
        JdkIdGenerator jdkIdGenerator = new JdkIdGenerator();
        AlternativeJdkIdGenerator alternativeJdkIdGenerator = new AlternativeJdkIdGenerator();
        SimpleIdGenerator simpleIdGenerator = new SimpleIdGenerator();
        Instant start;
        Instant end;
        int count = 1000000;
        //jdkIdGenerator
        start = Instant.now();
        for (int i = 0; i < count; i++) {
            jdkIdGenerator.generateId();
        }
        end = Instant.now();
        System.out.println("jdkIdGenerator循环" + count + "次耗时:" + Duration.between(start, end).toMillis() + "ms");
        //alternativeJdkIdGenerator
        start = Instant.now();
        for (int i = 0; i < count; i++) {
            alternativeJdkIdGenerator.generateId();
        }
        end = Instant.now();
        System.out.println("alternativeJdkIdGenerator循环" + count + "次耗时:" + Duration.between(start, end).toMillis() + "ms");
        //simpleIdGenerator
        start = Instant.now();
        for (int i = 0; i < count; i++) {
            simpleIdGenerator.generateId();
        }
        end = Instant.now();
        System.out.println("simpleIdGenerator循环" + count + "次耗时:" + Duration.between(start, end).toMillis() + "ms");
    }



发现仅仅循环生成100万次,Spring提供的算法性能远远高于JDK的。因此建议大家以后使用AlternativeJdkIdGenerator去生成UUID,性能会更好一点


缺点是:还需要new对象才能使用,不能通过类名直接调用静态方法,当然我们可以二次封装。另外,一般输出串我们都会进一步这么处理:.toString().replace("-", "")


Assert 断言工具类


Assert断言工具类,通常用于数据合法性检查。Assert断言工具类,通常用于数据合法性检查.

if (message== null || message.equls("")) {  
    throw new IllegalArgumentException("输入信息错误!");  
} 

用Assert工具类上面的代码可以简化为:Assert.hasText((message, "输入信息错误!");

下面介绍常用的断言方法的使用:



Assert.notNull(Object object, "object is required")    -    对象非空 
Assert.isTrue(Object object, "object must be true")   -    对象必须为true   
Assert.notEmpty(Collection collection, "collection must not be empty")    -    集合非空  
Assert.hasLength(String text, "text must be specified")   -    字符不为null且字符长度不为0   
Assert.hasText(String text, "text must not be empty")    -     text 不为null且必须至少包含一个非空格的字符  
Assert.isInstanceOf(Class clazz, Object obj, "clazz must be of type [clazz]")    -    obj必须能被正确造型成为clazz 指定的类

junit也提供断言工具类,但是我们只能在单元测试中使用,而Spring提供的这个,哪儿都能使用,还是比较方便的


PathMatcher 路径匹配器


Spring提供的实现:AntPathMatcher Ant路径匹配规则

(1)SpringMVC的路径匹配规则是依照Ant的来的,实际上不只是SpringMVC,整个Spring框架的路径解析都是按照Ant的风格来的;

(2)AntPathMatcher不仅可以匹配Spring的@RequestMapping路径,也可以用来匹配各种字符串,包括文件路径等。


你是否曾今在你们的Filter里看过类似下面的代码?

image.png


这种所谓的白名单URL这样来匹配,可谓非常的不优雅,而且通过穷举法的扩展性不可为不差。因此下面举几个例子来介绍此匹配器的用法,以后建议使用它吧~


        PathMatcher pathMatcher = new AntPathMatcher();
        //这是我们的请求路径  需要被匹配(理解成匹配controller吧 就很容易理解了)
        String requestPath = "/user/list.htm?username=aaa&departmentid=2&pageNumber=1&pageSize=20";//请求路径
        //路径匹配模版
        String patternPath = "/user/list.htm**";
        assertTrue(pathMatcher.match(patternPath, requestPath));


NT方式的通配符有三种:

?(匹配任何单字符),*(匹配0或者任意数量的字符),**(匹配0或者更多的目录)

url路径匹配规则说明:


image.png


举一些常用案例:


    @Test
    public void fun1() {
        PathMatcher pathMatcher = new AntPathMatcher();
        // 精确匹配
        assertTrue(pathMatcher.match("/test", "/test"));
        assertFalse(pathMatcher.match("test", "/test"));
        //测试通配符?
        assertTrue(pathMatcher.match("t?st", "test"));
        assertTrue(pathMatcher.match("te??", "test"));
        assertFalse(pathMatcher.match("tes?", "tes"));
        assertFalse(pathMatcher.match("tes?", "testt"));
        //测试通配符*
        assertTrue(pathMatcher.match("*", "test"));
        assertTrue(pathMatcher.match("test*", "test"));
        assertTrue(pathMatcher.match("test/*", "test/Test"));
        assertTrue(pathMatcher.match("*.*", "test."));
        assertTrue(pathMatcher.match("*.*", "test.test.test"));
        assertFalse(pathMatcher.match("test*", "test/")); //注意这里是false 因为路径不能用*匹配
        assertFalse(pathMatcher.match("test*", "test/t")); //这同理
        assertFalse(pathMatcher.match("test*aaa", "testblaaab")); //这个是false 因为最后一个b无法匹配了 前面都是能匹配成功的
        //测试通配符** 匹配多级URL
        assertTrue(pathMatcher.match("/*/**", "/testing/testing"));
        assertTrue(pathMatcher.match("/**/*", "/testing/testing"));
        assertTrue(pathMatcher.match("/bla/**/bla", "/bla/testing/testing/bla/bla")); //这里也是true哦
        assertFalse(pathMatcher.match("/bla*bla/test", "/blaXXXbl/test"));
        assertFalse(pathMatcher.match("/????", "/bala/bla"));
        assertFalse(pathMatcher.match("/**/*bla", "/bla/bla/bla/bbb"));
        assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing/"));
        assertTrue(pathMatcher.match("/*bla*/**/bla/*", "/XXXblaXXXX/testing/testing/bla/testing"));
        assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing"));
        assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing.jpg"));
        assertTrue(pathMatcher.match("/foo/bar/**", "/foo/bar"));
        //这个需要特别注意:{}里面的相当于Spring MVC里接受一个参数一样,所以任何东西都会匹配的
        assertTrue(pathMatcher.match("/{bla}.*", "/testing.html"));
        assertFalse(pathMatcher.match("/{bla}.htm", "/testing.html")); //这样就是false了
    }


注意事项:

1、AntPathMatcher不仅可以匹配URL路径,也可以匹配文件路径。但是需要注意AntPathMatcher也有有参构造,传递路径分隔符参数pathSeparator(若不传,默认值为/),对于文件路径的匹配来说,则需要根据不同的操作系统来传递各自的文件分隔符,以此防止匹配文件路径错误。


AntPathMatcher默认路径分隔符为“/”,而在匹配文件路径时,需要注意Windows下路径分隔符为“\”,Linux下为“/”。靠谱写法如下两种方式:

AntPathMatcher matcher = new AntPathMatcher(File.separator);
AntPathMatcher matcher = new AntPathMatcher(System.getProperty("file.separator"));

2、最长匹配规则(has more characters),即越精确的模式越会被优先匹配到。例如,URL请求/app/dir/file.jsp,现在存在两个路径匹配模式/**/.jsp和/app/dir/.jsp,那么会根据模式/app/dir/*.jsp来匹配。


ConcurrentReferenceHashMap


ConcurrentReferenceHashMap是自spring3.2后增加的一个同步的软(虚)引用Map。

这个工具类厉害了。我们知道java的引用类型一共分四种【小家java】引用类型(强引用、软引用、弱引用、虚引用),JDK也为我们提供了

WeakHashMap来使用。但是,但是它并不是线程安全的,因此刚好Spring给我们功提供这个工具类:ConcurrentReferenceHashMap满足了我们对线程安全的弱、软引用的需求。线面通过一个示例体验一把:

    @Test
    public void fun1() throws InterruptedException {
        String key = new String("key");
        String value = new String("val");
        Map<String, String> map = new ConcurrentReferenceHashMap<>(8, ConcurrentReferenceHashMap.ReferenceType.WEAK);
        map.put(key, value);
        System.out.println(map); //{key=val}
        key = null;
        System.gc();
        //等待一会 确保GC能够过来
        TimeUnit.SECONDS.sleep(5);
        System.out.println(map); //{}
    }


我们发现当我们吧key置为null后,垃圾回收器会回收掉这部分内存。这就是弱、虚引用的作用,主要用来防止OOM。


查看ConcurrentReferenceHashMap源码发现起底层实现依赖的是RefrenceQueue完成自动移除操作。时间有限就写到这里。有时间再进行完善。 当然还有保证线程安全的代码,也是很重要的

DefaultPropertiesPersister


这个类本身没有什么特别的,就是代理了JDK的Properties类而已。但写到此处是觉得Spring优秀就优秀在它强大的对扩展开放的原则体现。


比如如果我们需要对配置文件进行解密(比如数据库连接密码不能明文),这些操作通过复写这些扩展类的某些方法来做,将特别的优雅。

spring启动时,解密配置文件的密文


DigestUtils


可以对字节数组、InputStream流生成摘要。10禁止或者16进制都行

FastByteArrayOutputStream


可以说是Spring实现的加强版的ByteArrayOutputStream。为什么加强了呢?其实底层原理是Spring采用了一个LinkedList来作为缓冲区:

  // The buffers used to store the content bytes
  private final LinkedList<byte[]> buffers = new LinkedList<>();


ByteArrayOutputStream直接使用的字节数组。


protected byte buf[];

这样每一次扩容中分配一个数组的空间,并当该数据放入到List中。相当于批量的操作,而ByteArrayOutputStream内部实现为一个数组每一次扩容需要重新分配空间并将数据复制到新数组中。效率高下立判了~因此推荐使用


相关文章
|
3月前
|
IDE Java 数据库连接
解决Java环境中无法识别org.mybatis.spring.annotation.MapperScan的问题。
祝你好运,在这场MyBatis的魔法冒险中获得胜利!记住,魔法书(官方文档)永远是你最好的朋友。
236 18
|
2月前
|
Java 数据库连接 API
Java 8 + 特性及 Spring Boot 与 Hibernate 等最新技术的实操内容详解
本内容涵盖Java 8+核心语法、Spring Boot与Hibernate实操,按考试考点分类整理,含技术详解与代码示例,助力掌握最新Java技术与应用。
91 2
|
3月前
|
Java 数据库连接 API
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
145 1
|
3月前
|
SQL Java 数据库
解决Java Spring Boot应用中MyBatis-Plus查询问题的策略。
保持技能更新是侦探的重要素质。定期回顾最佳实践和新技术。比如,定期查看MyBatis-Plus的更新和社区的最佳做法,这样才能不断提升查询效率和性能。
143 1
|
4月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
|
3月前
|
Java 调度 流计算
基于Java 17 + Spring Boot 3.2 + Flink 1.18的智慧实验室管理系统核心代码
这是一套基于Java 17、Spring Boot 3.2和Flink 1.18开发的智慧实验室管理系统核心代码。系统涵盖多协议设备接入(支持OPC UA、MQTT等12种工业协议)、实时异常检测(Flink流处理引擎实现设备状态监控)、强化学习调度(Q-Learning算法优化资源分配)、三维可视化(JavaFX与WebGL渲染实验室空间)、微服务架构(Spring Cloud构建分布式体系)及数据湖建设(Spark构建实验室数据仓库)。实际应用中,该系统显著提升了设备调度效率(响应时间从46分钟降至9秒)、设备利用率(从41%提升至89%),并大幅减少实验准备时间和维护成本。
239 0
|
3月前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
361 0
|
3月前
|
监控 安全 Java
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
498 0