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); } }
最后是这几个方法:
针对指定类型上的所有方法,依次调用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处理的源码如下:(仅供参考)
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重要协议端口号,供以参考
另外说明: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"));