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

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

FileCopyUtils、FileSystemUtils、StreamUtils


都是操作文件、操作流的一些工具类。这里就不做过多的介绍了,因为还是比较简单的。


LinkedCaseInsensitiveMap 、LinkedMultiValueMap


不区分大小写的有序map;底层代理了LinkedHashMap,因此它能保证有序。此Map的意义在于:在编写比如MaBatis这种类似的自动封装框架的时候,特备有用。


数据库本身对大小写不敏感(我使用的是mysql),但是创建表格的时候,数据库里面字段都会默认小写,所以MyBatis映射的时候,key也会映射成小写,可以用LinkedCaseInsensitiveMap(key值不区分大小写的LinkedMap)来处理。


LinkedCaseInsensitiveMap的key一定是String


现在我随手写个Demo,感受一下吧:

    @Test
    public void fun1() {
        Map<String, Object> map = new LinkedCaseInsensitiveMap<>();
        map.put("a", 1);
        map.put("A", 1);
        System.out.println(map); //{A=1}
        System.out.println(map.get("a")); //1 map里面key是小写的a,通过大写的A也能get出来结果
    }

LinkedMultiValueMap:见名之意,一个key对应多个value。废话不多说,直接感受一把就知道了


    @Test
    public void fun1() {
        //用Map接的时候  请注意第二个泛型 是个List哦
        //Map<String, List<Integer>> map = new LinkedMultiValueMap<>();
        LinkedMultiValueMap<String, Integer> map = new LinkedMultiValueMap<>();
        //此处务必注意,如果你还是用put方法  那是没有效果的 同一个key还是会覆盖
        //map.put("a", Arrays.asList(1));
        //map.put("a", Arrays.asList(1));
        //map.put("a", Arrays.asList(1));
        //System.out.println(map); //{a=[1]}
        //请用add方法
        map.add("a", 1);
        map.add("a", 1);
        map.add("a", 1);
        System.out.println(map); //{a=[1, 1, 1]}
    }



个人感觉没有Apache Common提供的好用。但是一般来说也足够用了~


PropertyPlaceholderHelper


作用:将字符串里的占位符内容,用我们配置的properties里的替换。这个是一个单纯的类,没有继承没有实现,而且也没简单,没有依赖Spring框架其他的任何类。


StringValueResolver是一个转化String类型数据的接口,真正更新属性的api实现竟然是在PropertyPlaceholderHelper#parseStringValue


因此现在知道此类的重要性了,下面演示一下Demo,知道怎么使用即可(其实在Spring容器环境下,这些都退调用者是透明的,除非自己要书写框架性的东西):

配置文件如下:


name=wangzha
age=18
sex=man
name18man=love


    public static void main(String[] args) throws Exception {
        String a = "{name}{age}{sex}";
        String b = "{name{age}{sex}}";
        PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("{", "}");
        InputStream in = new BufferedInputStream(new FileInputStream(new File("D:\\work\\remotegitcheckoutproject\\myprojects\\java\\boot2-demo1\\src\\main\\resources\\application.properties")));
        Properties properties = new Properties();
        properties.load(in);
        //==============开始解析此字符串==============
        System.out.println("替换前:" + a); //替换前:{name}{age}{sex}
        System.out.println("替换后:" + propertyPlaceholderHelper.replacePlaceholders(a, properties)); //替换后:wangzha18man
        System.out.println("====================================================");
        System.out.println("替换前:" + b); //替换前:{name{age}{sex}}
        System.out.println("替换后:" + properties); //替换后:love  最后输出love,证明它是从内往外一层一层解析的
    }


显然@Value注解或者其余spel表达式的东西,都得依赖于这个来做。


这个掌握了,让我们自定义支持的表达式的时候,我们也可以高大上的说,我的格式支持spel表达式SpelExpressionParser。更加的灵活了


SpringVersion、SpringBootVersion 获取当前Spring版本号


    public static void main(String[] args) {
        System.out.println(SpringVersion.getVersion()); //5.0.6.RELEASE
        System.out.println(SpringBootVersion.getVersion()); //2.0.2.RELEASE
    }


ReflectionUtils 反射工具类


反射在容器中使用是非常频繁的了,这些方法一般在Spring框架内部使用。当然现在Spring都成为实际的规范了,所以我们也可以直接拿来使用。

public static Field findField(Class<?> clazz, String name);
public static Field findField(Class<?> clazz, @Nullable String name, @Nullable Class<?> type);
public static void setField(Field field, @Nullable Object target, @Nullable Object value);


该方法是从类里面找到字段对象。(private以及父类的都会找哟,但是static的就不会啦)


public static Object getField(Field field, @Nullable Object target);


这个很明显,就是拿到该对象指定字段的值,示例如下:


    public static void main(String[] args) {
        Person person = new Person("fsx", 18);
        Field field = ReflectionUtils.findField(Person.class, "name");
        field.setAccessible(true); //注意,如果是private的属性,请加上这一句,否则抛出异常:can not access a member of class com.fsx.boot2demo1.bean.Person with modifiers "private"
        System.out.println(ReflectionUtils.getField(field, person)); //fsx
    }
public static Method findMethod(Class<?> clazz, String name);
public static Method findMethod(Class<?> clazz, String name, @Nullable Class<?>... paramTypes);
public static Object invokeMethod(Method method, @Nullable Object target); //这个不需要自己处理异常哦
public static Object invokeMethod(Method method, @Nullable Object target, @Nullable Object... args);

示例:

    public static void main(String[] args) {
        Person person = new Person("fsx", 18);
        System.out.println(ReflectionUtils.findMethod(Person.class, "clone")); //protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
        System.out.println(ReflectionUtils.findMethod(Person.class, "getName")); //public java.lang.String com.fsx.boot2demo1.bean.Person.getName()
        System.out.println(ReflectionUtils.findMethod(Person.class, "setName", String.class)); //public void com.fsx.boot2demo1.bean.Person.setName(java.lang.String)
        System.out.println(ReflectionUtils.findMethod(Person.class, "privateMethod")); //private void com.fsx.boot2demo1.bean.Person.privateMethod()
    }


也是一样非常的强大。private、父类方法都能获取到。


所有的反射相关的异常,其实都可以交给下面来处理:


public static void handleReflectionException(Exception ex);
public static void rethrowRuntimeException(Throwable ex);


boolean declaresException(Method method, Class<?> exceptionType); //判断一个方法上是否声明了指定类型的异常
boolean isPublicStaticFinal(Field field); //判断字段是否是public static final的
boolean isEqualsMethod(Method method); //判断该方法是否是equals方法
boolean isHashCodeMethod(Method method);
boolean isToStringMethod(Method method);
boolean isObjectMethod(Method method); //判断该方法是否是Object类上的方法
public static void makeAccessible(Field field); //将一个字段设置为可读写,主要针对private字段
void makeAccessible(Method method);
void makeAccessible(Constructor<?> ctor);


在AopUtils中也有这几个isXXX方法,是的,其实AopUtils中的isXXX方法就是调用的ReflectionUtils的这几个方法的;所以可见此工具类的强大


public static Method[] getAllDeclaredMethods(Class<?> leafClass);
public static Method[] getUniqueDeclaredMethods(Class<?> leafClass);


看个栗子:


    public static void main(String[] args) {
        Person person = new Person("fsx", 18);
        Method[] allDeclaredMethods = ReflectionUtils.getAllDeclaredMethods(Person.class);
        //我们发现  这个方法可以把所有的申明的方法都打印出来。包含private和父类的   备注:重复方法都会拿出来。比如此处的toString方法 子类父类的都有
        for (Method method : allDeclaredMethods) {
            System.out.println(method);
        }
        System.out.println("------------------------------------");
        //针对于上面的结果过滤。只会保留一个同名的方法(保留子类的)
        Method[] uniqueDeclaredMethods = ReflectionUtils.getUniqueDeclaredMethods(Person.class);
        for (Method method : uniqueDeclaredMethods) {
            System.out.println(method);
        }
    }


最后是这几个方法:


image.png


针对指定类型上的所有方法,依次调用MethodCallback回调;看个源码就知道这个方法的作用:


public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
    Method[] methods = getDeclaredMethods(clazz);
    for (Method method : methods) {
        try {
            mc.doWith(method);
        }catch (IllegalAccessException ex) {
            throw new IllegalStateException("...");
        }
    }
}


其实实现很简单,就是得到类上的所有方法,然后执行回调接口;这个方法在Spring针对bean的方法上的标签处理时大量使用,比如@Init,@Resource,@Autowire等标签的预处理;

Spring处理的源码如下:(仅供参考)


image.png


image.png


image.png


ResourceUtils

Spring 提供了一个 ResourceUtils 工具类,它支持“classpath:”和“file:”的地址前缀,它能够从指定的地址加载文件资源。(其实还支持“jar:和war:前缀”)

public abstract class ResourceUtils {
  public static final String CLASSPATH_URL_PREFIX = "classpath:";
  public static final String FILE_URL_PREFIX = "file:";
  public static final String JAR_URL_PREFIX = "jar:";
  public static final String WAR_URL_PREFIX = "war:";
  ...
  // 是否是一个URL
  public static boolean isUrl(@Nullable String resourceLocation) {
    if (resourceLocation == null) {
      return false;
    }
    // 对classpath:进行了特殊的照顾
    if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
      return true;
    }
    try {
      new URL(resourceLocation);
      return true;
    }
    catch (MalformedURLException ex) {
      return false;
    }
  }
  public static URL getURL(String resourceLocation) throws FileNotFoundException {...}
  public static File getFile(String resourceLocation) throws FileNotFoundException {...}
  public static File getFile(URL resourceUrl) throws FileNotFoundException {...}
  public static File getFile(URI resourceUri) throws FileNotFoundException {...}
  public static File getFile(URI resourceUri, String description) throws FileNotFoundException {...}
  // 判断
  public static boolean isFileURL(URL url) {
    // 均是和protocol 这个协议有关的~~~
    String protocol = url.getProtocol();
    return (URL_PROTOCOL_FILE.equals(protocol) || URL_PROTOCOL_VFSFILE.equals(protocol) ||
        URL_PROTOCOL_VFS.equals(protocol));
  }
  public static boolean isJarURL(URL url) {...}
  // @since 4.1
  public static boolean isJarFileURL(URL url) {...}
  // URL和URI的转换
  public static URI toURI(URL url) throws URISyntaxException {
    return toURI(url.toString());
  }
  public static URI toURI(String location) throws URISyntaxException {
    return new URI(StringUtils.replace(location, " ", "%20"));
  }
}

Demo:


    public static void main(String[] args) throws FileNotFoundException {
        File file = ResourceUtils.getFile("classpath:application.properties");
        System.out.println(file); //D:\work\remotegitcheckoutproject\myprojects\java\boot2-demo1\target\classes\application.properties
        System.out.println(ResourceUtils.isUrl("classpath:application.properties")); //true
        //注意此处输出的路径为正斜杠 ‘/’的  上面直接输出File是反斜杠的(和操作系统相关)
        System.out.println(ResourceUtils.getURL("classpath:application.properties")); //file:/D:/work/remotegitcheckoutproject/myprojects/java/boot2-demo1/target/classes/application.properties
    }

备注:若你在使用过程中,发现ResourceUtils.getFile()死活都找不到文件的话,那我提供一个建议:是否是在jar包内使用了此工具类,一般不建议在jar包内使用。另外,提供一个代替方案:可解决大多数问题


    public static void main(String[] args) {
        ClassPathResource resource = new ClassPathResource("application.properties");
        System.out.println(resource); //class path resource [application.properties]
    }

SerializationUtils


这个工具就不做过多解释了。提供了两个方法:对象<–>二进制的相互转化。(基于源生JDK的序列化方式)

public static byte[] serialize(@Nullable Object object);
public static Object deserialize(@Nullable byte[] bytes);


请注意,对象需要实现Serializable接口哦


SocketUtils


提供给我们去系统找可用的Tcp、Udp端口来使用。有的时候确实还蛮好用的,必进端口有时候不用写死了,提高灵活性


    public static void main(String[] args) {
        System.out.println(SocketUtils.PORT_RANGE_MAX); //65535 最大端口号
        System.out.println(SocketUtils.findAvailableTcpPort()); //45569 随便找一个可用的Tcp端口 每次执行值都不一样哦
        System.out.println(SocketUtils.findAvailableTcpPort(1000, 2000)); //1325 从指定范围内随便找一个端口
        //找一堆端口出来  并且是排好序的
        System.out.println(SocketUtils.findAvailableTcpPorts(10, 1000, 2000)); //[1007, 1034, 1287, 1483, 1494, 1553, 1577, 1740, 1963, 1981]
        //UDP端口的找寻 同上
        System.out.println(SocketUtils.findAvailableUdpPort()); //12007
    }

其长度都是16个bit,所以端口号范围是0到(2^16-1),即 0到 65535。其中0到1023是IANA规定的系统端口,即系统保留窗口。例如HTTP为80端口,DNS服务为53端口。下面列出常用tcp和udp重要协议端口号,供以参考


image.png


image.png

另外说明:TCP、UDP可以绑定同一端口来进行通信。每个端口都拥有一个叫端口号(port number)的整数型标识符,用于区别不同端口。由于TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号也相互独立,如TCP有一个255号端口,UDP也可以有一个255号端口,二者并不冲突。

StringUtils


Spring提供的字符串处理类。再结合Apache提供的,绝对的够用了。因此平时code过程中,绝对禁止程序员再自定义StringUtils工具类。


Spring为了最依赖原则,自己实现了一个StringUtils,这里分类进行介绍:


判断类

属于该类别的方法都是在对字符串进行一些判定操作:

   //判断类:
    // boolean isEmpty(Object str):字符串是否为空或者空字符串:""
    // boolean hasLength(CharSequence str):字符串是否为空,或者长度为0
    // boolean hasText(String str):字符串是否有内容(不为空,且不全为空格)
    assertFalse(StringUtils.hasText("   "));
    // boolean containsWhitespace(String str):字符串是否包含空格
    assertTrue(StringUtils.containsWhitespace("a b"));



相关文章
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
88 2
|
2天前
|
Java Spring
Java Spring Boot监听事件和处理事件
通过上述步骤,我们可以在Java Spring Boot应用中实现事件的发布和监听。事件驱动模型可以帮助我们实现组件间的松耦合,提升系统的可维护性和可扩展性。无论是处理业务逻辑还是系统事件,Spring Boot的事件机制都提供了强大的支持和灵活性。希望本文能为您的开发工作提供实用的指导和帮助。
32 15
|
1月前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
60 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
2月前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
245 12
基于开源框架Spring AI Alibaba快速构建Java应用
|
3月前
|
Java 数据库连接 开发者
Spring 框架:Java 开发者的春天
【10月更文挑战第27天】Spring 框架由 Rod Johnson 在 2002 年创建,旨在解决 Java 企业级开发中的复杂性问题。它通过控制反转(IOC)和面向切面的编程(AOP)等核心机制,提供了轻量级的容器和丰富的功能,支持 Web 开发、数据访问等领域,显著提高了开发效率和应用的可维护性。Spring 拥有强大的社区支持和丰富的生态系统,是 Java 开发不可或缺的工具。
|
3月前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
145 2
|
2月前
|
Java 数据库连接 API
Spring 框架的介绍(Java EE 学习笔记02)
Spring是一个由Rod Johnson开发的轻量级Java SE/EE一站式开源框架,旨在解决Java EE应用中的多种问题。它采用非侵入式设计,通过IoC和AOP技术简化了Java应用的开发流程,降低了组件间的耦合度,支持事务管理和多种框架的无缝集成,极大提升了开发效率和代码质量。Spring 5引入了响应式编程等新特性,进一步增强了框架的功能性和灵活性。
55 0
|
2月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
46 0
|
前端开发 Java 数据库
Java面试题 - Spring
Java面试题 - Spring
149 0
|
6月前
|
Java 应用服务中间件 开发者
Java面试题:解释Spring Boot的优势及其自动配置原理
Java面试题:解释Spring Boot的优势及其自动配置原理
131 0

热门文章

最新文章