前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【小家Spring】Spring Framework提供的实用纯Java工具类大合集(二)

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

作者头像
YourBatman
发布2019-09-03 15:25:44
1.2K0
发布2019-09-03 15:25:44
举报
文章被收录于专栏:BAT的乌托邦
前言

接着上一篇

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

继续来介绍Spring提供的好用的一些工具类。

Assert

这是Spring提供给我们的断言工具,是以抛异常的方式来处理的。

若你是自己的书写框架的时候,可以使用它的,而不用自己各种去if判空了

代码语言:javascript
复制
    public static void main(String[] args) {
        Integer param = 1;
        Assert.state(param == 2, "param的值不为2,请校对~");

        //Assert.hasText();
        //Assert.hasLength();
        //Assert.notNull();
        //Assert.notEmpty();
        //...
    }
// 输出
Exception in thread "main" java.lang.IllegalStateException: param的值不为2,请校对~
ClassUtils:非常非常重要的一个工具类

这是关于类级别相关的工具类,虽然只是提供给Spring框架内部使用,但是很多方法还是有一定使用价值,并且理解这些方法的实现,也是有一定价值的

该工具类在Spring框架中可谓使用非常广泛

首先ClassUtils是一个非常大的工具类,提供了很多缓存数据和初始化内容

代码语言:javascript
复制
public abstract class ClassUtils {
	
	// 这些常量 挺重要的  都是public的  我们也可以使用   这些都遵循了Java的命名规范
	public static final String ARRAY_SUFFIX = "[]";
	private static final String INTERNAL_ARRAY_PREFIX = "[";
	// 这个非常有意思:如果你是八大基本类型(PRIMITIVE类型)的数组类型, toString()方法是"[A"/"[B"...等等
	// 但是如果你是new Person[0]或者new Object[0]这种数组类型,全都是"[L"打头得,这个非常有规律性
	private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
	private static final char PACKAGE_SEPARATOR = '.';
	private static final char PATH_SEPARATOR = '/';
	// 是否是内部类
	private static final char INNER_CLASS_SEPARATOR = '$';
	// 这个符号,用来判断是否是CGLIB的代理类
	public static final String CGLIB_CLASS_SEPARATOR = "$$";
	public static final String CLASS_FILE_SUFFIX = ".class";

	// 下面这个很重要,提高效率必备---缓存   他们都是private的
	// 缓存八大基本数据类型 --> 包装类型的映射 所有长度相同
	private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap<>(8);
	// 和上面区别:上面的key是这里的value
	private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new IdentityHashMap<>(8);
	// 保存所遇的基础数据类型 8 + 8(对应数组类型) + void.class 一共会有17个元素
	private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<>(32);
	
	// 顾名思义:它是缓存一些常用的Class类型。key为class.getName()  value为Class本身
	// 比如:上面所列的17个、 还有包装类型的数组(8个) + Number.class/Class.class... + Enum.class/Exception.class/ List.clss... 总之就是缓存比较常用的一些类型吧
	private static final Map<String, Class<?>> commonClassCache = new HashMap<>(64);
	// 缓存Java语言的一些常用接口:
	//Serializable.class, Externalizable.class, Closeable.class, AutoCloseable.class, Cloneable.class, Comparable.class
	private static final Set<Class<?>> javaLanguageInterfaces;

	// 这个方法非常常用:按照获取当前线程上下文类加载器-->获取当前类类加载器-->获取系统启动类加载器的顺序来获取
	@Nullable
	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		}
		catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back...
		}
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			cl = ClassUtils.class.getClassLoader();
			if (cl == null) {
				// getClassLoader() returning null indicates the bootstrap ClassLoader
				try {
					cl = ClassLoader.getSystemClassLoader();
				}
				catch (Throwable ex) {
					// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
				}
			}
		}
		return cl;
	}

	//这个方法较为简单,使用传入的classloader替换线程的classloader;使用场景,比如一个线程的classloader和spring的classloader不一致的时候,就可以使用这个方法替换
	@Nullable
	public static ClassLoader overrideThreadContextClassLoader(@Nullable ClassLoader classLoaderToUse) {
		Thread currentThread = Thread.currentThread();
		ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
		if (classLoaderToUse != null && !classLoaderToUse.equals(threadContextClassLoader)) {
			currentThread.setContextClassLoader(classLoaderToUse);
			return threadContextClassLoader;
		}
		else {
			return null;
		}
	}

	// 看名字就知道,是Class.forName的一个增强版本;通过指定的classloader加载对应的类;除了能正常加载普通的类型,``还能加载简单类型,数组,或者内部类``
	// 数组是通过Array.newInstance创建出来的,然后.getClass()
	public static Class<?> forName(String name, @Nullable ClassLoader classLoader){
		...
	}
}

看下测试代码:

代码语言:javascript
复制
	//可以看到,简单类型int,数组String[]和内部类(内部类通过父类.子类的方式即可获取)
    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();

        // 加载基本数据类型int都可议
        System.out.println(ClassUtils.forName("int", defaultClassLoader)); // int
        System.out.println(ClassUtils.forName("java.lang.String[]", defaultClassLoader)); //class [Ljava.lang.String;
        System.out.println(ClassUtils.forName("java.lang.Thread.State", defaultClassLoader)); //class java.lang.Thread$State
    }

	//和forName方法相同,内部就是直接调用的forName方法,只是抛出的异常不一样而已;
	public static Class<?> resolveClassName(String className, @Nullable ClassLoader classLoader){
		...
	}

	// 这个在Spring里也有大量的应用:判断某个是否存在  内部依赖于forName()方法 下面写个Demo
	public static boolean isPresent(String className, @Nullable ClassLoader classLoader) { ... }

	// 专门处理基本类型  效率非常的高
	public static Class<?> resolvePrimitiveClassName(String name) {
	    Class<?> result = null;
	    // 简单类型,最长值不要超过8,如果超过8,反而可以忽略了
	    if (name != null && name.length() <= 8) {
	        // Could be a primitive - likely.
	        result = primitiveTypeNameMap.get(name);
	    }
    return result;
	
	//判断一个类型是否在指定类加载器中可见  它在下面方法`getAllInterfacesForClassAsSet`会有用到
	boolean isVisible(Class<?> clazz, ClassLoader classLoader)
}

给个Demo如下:

代码语言:javascript
复制
    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();

        System.out.println(ClassUtils.isPresent("java.lang.String", defaultClassLoader)); //true
        System.out.println(ClassUtils.isPresent("java.lang.xxx", defaultClassLoader)); //false

        System.out.println(ClassUtils.resolvePrimitiveClassName("int")); //int
        System.out.println(ClassUtils.resolvePrimitiveClassName("aaa")); //null  如果不存在,就返回null

        // 这里以defaultClassLoader为例
        System.out.println(ClassUtils.isVisible(String.class, defaultClassLoader)); // true

    }
代码语言:javascript
复制
	//判定一个类是否是简单类型的包装类;
	boolean isPrimitiveWrapper(Class<?> clazz);
	// 基本类型或者包装类型
	boolean isPrimitiveOrWrapper(Class<?> clazz)
	// 基本类型的数组类型
	public static boolean isPrimitiveArray(Class<?> clazz);
	// 基本类型的包装类型的数组类型
	public static boolean isPrimitiveWrapperArray(Class<?> clazz);
	//如果传入的类型是一个简单类型,返回这个简单类型的包装类型
	public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz);

demo演示:

代码语言:javascript
复制
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(ClassUtils.isPrimitiveWrapper(Integer.class)); //true
        System.out.println(ClassUtils.isPrimitiveWrapper(int.class)); //false
        System.out.println(ClassUtils.isPrimitiveOrWrapper(int.class)); //true

        System.out.println(ClassUtils.isPrimitiveArray(Integer[].class)); //false
        System.out.println(ClassUtils.isPrimitiveArray(int[].class)); // true
        System.out.println(ClassUtils.isPrimitiveWrapperArray(int[].class)); //false

        // 传进去事包装类型  最终返回的是基本类型
        Class<?> clazz = ClassUtils.resolvePrimitiveIfNecessary(Integer[].class);
        System.out.println(clazz); //class [Ljava.lang.Integer;
        System.out.println(Integer[].class); //class [Ljava.lang.Integer;
        System.out.println(clazz == Integer[].class); //true
    }
代码语言:javascript
复制
	public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) { ... }
	public static boolean isAssignableValue(Class<?> type, @Nullable Object value) { ... }

demo演示:

代码语言:javascript
复制
    public static void main(String[] args) {
        System.out.println(Object.class.isAssignableFrom(Integer.class)); // true
        System.out.println(Object.class.isAssignableFrom(int.class)); // false  请注意这里返回的是false

        // 但是下面这么弄  就都返回true了
        System.out.println(ClassUtils.isAssignable(Object.class, Integer.class)); //true
        System.out.println(ClassUtils.isAssignable(Object.class, int.class)); // true

        // 有个更简便的方式 对象参与比较
        Integer i = 0;
        System.out.println(ClassUtils.isAssignableValue(Object.class, i)); //true
    }
代码语言:javascript
复制
	public static String convertResourcePathToClassName(String resourcePath) {}
	public static String convertClassNameToResourcePath(String className) {}
	//在指定类的所属包下面,寻找一个资源文件,并返回该资源文件的文件路径
	public static String addResourcePathToPackagePath(Class<?> clazz, String resourceName) {}
	public static String classPackageAsResourcePath(@Nullable Class<?> clazz) {}
	public static String classNamesToString(Class<?>... classes) {}
	public static String classNamesToString(@Nullable Collection<Class<?>> classes) {}

demo show:

代码语言:javascript
复制
    public static void main(String[] args) {
        //String filePath = "links\\fsx\\A.class";
        String filePath = "links/fsx/A.class";
        System.out.println(ClassUtils.convertResourcePathToClassName(filePath)); //links.fsx.A.class
        //System.out.println(ClassUtils.convertClassNameToResourcePath(filePath));

        //在指定类的所属包下面,寻找一个资源文件,并返回该资源文件的文件路径 java.lang.String
        System.out.println(ClassUtils.addResourcePathToPackagePath(String.class, "someResource.xml")); // java/lang/someResource.xml

        System.out.println(ClassUtils.classPackageAsResourcePath(String.class)); //java/lang

        // 打印classNames
        System.out.println(ClassUtils.classNamesToString(String.class, Integer.class)); //[java.lang.String, java.lang.Integer]
        System.out.println(ClassUtils.classNamesToString(Arrays.asList(String.class, Integer.class))); //[java.lang.String, java.lang.Integer]
    }
代码语言:javascript
复制
	//将类集合变成类型数组
	public static Class<?>[] toClassArray(Collection<Class<?>> collection) {
	//获取一个对象的所有接口
	public static Class<?>[] getAllInterfaces(Object instance) {
	//获取一个类型的所有接口
	public static Class<?>[] getAllInterfacesForClass(Class<?> clazz) {
	//获取指定类加载器下的指定类型的所有接口
	public static Class<?>[] getAllInterfacesForClass(Class<?> clazz, @Nullable ClassLoader classLoader) {

	//获取一个对象的所有接口,返回Set;(基本同上)  只是最后用Set返回   toClassArray()就成了上面所需要的数组
	public static Set<Class<?>> getAllInterfacesAsSet(Object instance) {
	public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz) {
	public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz, @Nullable ClassLoader classLoader) {

Demo:

代码语言:javascript
复制
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        // 拿到该实例实现的所有的接口
        System.out.println(Arrays.asList(ClassUtils.getAllInterfaces(list))); //[interface java.util.List, interface java.util.RandomAccess, interface java.lang.Cloneable, interface java.io.Serializable, interface java.util.Collection]
        System.out.println(ClassUtils.getAllInterfacesAsSet(list)); // 输出结果同上
    }
代码语言:javascript
复制
	// 这个方法很有意思:找到两个Class 的祖先类(也就是谁是父类就返回谁了)
	public static Class<?> determineCommonAncestor(@Nullable Class<?> clazz1, @Nullable Class<?> clazz2) {}

这个方法很有意思,Spring在Autowired自动注入AbstractAutowireCapableBeanFactory中有大量的应用:

代码语言:javascript
复制
    public static void main(String[] args) {
        System.out.println(ClassUtils.determineCommonAncestor(Integer.class,Long.class)); //class java.lang.Number  找到他们共同父类
        System.out.println(ClassUtils.determineCommonAncestor(Integer.class,Number.class)); //class java.lang.Number  若其中一个就是父类 就直接返回即可
        System.out.println(ClassUtils.determineCommonAncestor(Integer.class, Person.class)); //null  八竿子打不着就返回null吧(注意相当于是Object.class 直接返回null的)
    }
代码语言:javascript
复制
	// 是否是内部类
	public static boolean isInnerClass(Class<?> clazz) {
		return (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers()));
	}
	// 是否是CGLIB代理对象
	public static boolean isCglibProxy(Object object) {
		return isCglibProxyClass(object.getClass());
	}
	public static boolean isCglibProxyClass(@Nullable Class<?> clazz) {
		return (clazz != null && isCglibProxyClassName(clazz.getName()));
	}
	public static boolean isCglibProxyClassName(@Nullable String className) {
		return (className != null && className.contains(CGLIB_CLASS_SEPARATOR));
	}

	// 获取用户定义的本来的类型,大部分情况下就是类型本身,主要针对cglib做了额外的判断,获取cglib代理之后的父类;
	public static Class<?> getUserClass(Object instance) {}
	// 获取一个对象的描述类型;一般来说,就是类名,能够正确处理数组,如果是JDK代理对象,能够正确输出其接口类型:
	public static String getDescriptiveType(@Nullable Object value) { ... }
	
	public static String getShortName(String className) {
	public static String getShortName(Class<?> clazz) {
	public static String getShortNameAsProperty(Class<?> clazz) {
	public static String getClassFileName(Class<?> clazz) {
	public static String getPackageName(Class<?> clazz) {
	public static String getPackageName(String fqClassName) {
	public static String getQualifiedName(Class<?> clazz) {

Demo show:

代码语言:javascript
复制
     public static void main(String[] args) {

        System.out.println(ClassUtils.getShortName("java.lang.String")); //String
        System.out.println(ClassUtils.getShortName(String.class)); //String
        System.out.println(ClassUtils.getShortNameAsProperty(String.class)); //String
        System.out.println(ClassUtils.getPackageName(String.class)); //java.lang
        System.out.println(ClassUtils.getPackageName("java.lang.String")); //java.lang
        // clazz.getTypeName()
        System.out.println(ClassUtils.getQualifiedName(String.class)); //java.lang.String
        System.out.println(String.class.getName()); //java.lang.String
        System.out.println(String.class.getTypeName()); //java.lang.String

        System.out.println(ClassUtils.getDescriptiveType(ArrayList.class)); //java.lang.Class  注意此处的输出


        ////java.lang.Class
        //System.out.println(ClassUtils.getDescriptiveType(getClass()));
        ////java.lang.String[]
        //System.out.println(ClassUtils.getDescriptiveType(new String[]{}));
        //
        ////com.sun.proxy.$Proxy20 implementing cn.wolfcode.springboot.utilstest.IEmployeeService,
        ////cn.wolfcode.springboot.utilstest.IAddition,
        ////org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised
        //System.out.println(ClassUtils.getDescriptiveType(service));
    }
}
代码语言:javascript
复制
	public static String getQualifiedMethodName(Method method) {
	public static String getQualifiedMethodName(Method method, @Nullable Class<?> clazz) {
	public static boolean hasConstructor(Class<?> clazz, Class<?>... paramTypes) {
	public static <T> Constructor<T> getConstructorIfAvailable(Class<T> clazz, Class<?>... paramTypes) {
	//判断类是否有指定的public方法
	public static boolean hasMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
	public static Method getMethod(Class<?> clazz, String methodName, @Nullable Class<?>... paramTypes) {
	public static Method getMethodIfAvailable(Class<?> clazz, String methodName, @Nullable Class<?>... paramTypes) {
		
	//获取指定类中匹配该方法名称的方法个数,包括非public方法;
	public static int getMethodCountForName(Class<?> clazz, String methodName) {
	//判定指定的类及其父类中是否包含指定方法名称的方法,包括非public方法;
	public static boolean hasAtLeastOneMethodWithName(Class<?> clazz, String methodName) {
	//获得最匹配的一个可以执行的方法; 和Overrid有关
	public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
	//该方法用于判定一个方法是否是用户可用的方法
	public static boolean isUserLevelMethod(Method method) {
		// 桥接方法,
		// method. isSynthetic方法:判定一个方法是否是虚构方法(synthetic method);什么是synthetic方法?由编译器创建的,非默认构造方法
		//(我们知道,类都有默认构造方法,当然重载了默认构造方法的除外,编译器都会生成一个默认构造方法的实现)在源码中没有对应的方法实现的方法都是虚构方法。
		// 比如上面介绍的bridge方法就是一个典型的synthetic方法;
		// isGroovyObjectMethod:判定一个方法是否是Groovy的方法,因为Spring支持Groovy,而Groovy的类都实现了groovy.lang.GroovyObject类;
		return (method.isBridge() || (!method.isSynthetic() && !isGroovyObjectMethod(method)));
	}
	public static Method getStaticMethod(Class<?> clazz, String methodName, Class<?>... args) {

很多方法依赖于ReflectionUtils,建议使用它吧

Introspector:内省

反射:反射就是让你可以通过名称来得到对象(类,属性,方法)的技术。例如我们可以通过类名来生成一个类的实例;知道了方法名,就可以调用这个方法;知道了属性名就可以访问这个属性的值

内省:内省(Introspector) 是Java 语言对 JavaBean 类属性、事件的一种缺省处理方法。所以它是位于Bean包下的:java.beans.Introspector,它有个方法BeanInfo bi = Introspector.getBeanInfo(demo.getClass(),Object.class);就能获取到一个BeanInfo,从而获取到每个属性值。

Struts将表单数据映射到JavaBean就是通过内省来实现的

这里面推荐两篇文章:

内省(一)之Introspector、BeanInfo、PropertyDescriptor

内省(二)之BeanUtils工具类

MethodIntrospector
代码语言:javascript
复制
// @since 4.2.3
// 定义彻底搜索元数据关联方法的算法,包括接口和父类,同时还处理参数化方法,以及接口和基于类的代理遇到的常见场景
// 通常,但不一定,用于查找带注释的处理程序方法~~~~~~~~~~~~~~
// 也就是说倘若你的注解啥的,在接口上也是可以的
public abstract class MethodIntrospector {

	// 核心方法:就是从指定的targetType里找到合适的方法。metadataLookup:用于过滤
	public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
		final Map<Method, T> methodMap = new LinkedHashMap<>();
		Set<Class<?>> handlerTypes = new LinkedHashSet<>();
		Class<?> specificHandlerType = null;
		
		// 如果该类型 不是JDK动态代理类型
		if (!Proxy.isProxyClass(targetType)) {
			specificHandlerType = ClassUtils.getUserClass(targetType);
			handlerTypes.add(specificHandlerType);
		}
		// 拿到该目标类型所有的实现的接口们~~~~~~~
		handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));

		// 遍历所有的需要处理的handlerTypes  然后一个个的处理
		for (Class<?> currentHandlerType : handlerTypes) {
			// 如果找到了specificHandlerType ,那就用它,否则就是currentHandlerType
			final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);

		 	// 使用的是ReflectionUtils.USER_DECLARED_METHODS 方法过滤器。
			ReflectionUtils.doWithMethods(currentHandlerType, method -> {
				Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
				// 对这个specificMethod 还会做进一步的处理~~~~
				T result = metadataLookup.inspect(specificMethod);
				if (result != null) {
					Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
					//==================================
					if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
						methodMap.put(specificMethod, result);
					}
				}
			}, ReflectionUtils.USER_DECLARED_METHODS);
		}

		return methodMap;
	}

	public static Set<Method> selectMethods(Class<?> targetType, final ReflectionUtils.MethodFilter methodFilter) {
		return selectMethods(targetType,
				(MetadataLookup<Boolean>) method -> (methodFilter.matches(method) ? Boolean.TRUE : null)).keySet();
	}

	public static Method selectInvocableMethod(Method method, Class<?> targetType) {
		if (method.getDeclaringClass().isAssignableFrom(targetType)) {
			return method;
		}
		try {
			String methodName = method.getName();
			Class<?>[] parameterTypes = method.getParameterTypes();
			for (Class<?> ifc : targetType.getInterfaces()) {
				try {
					return ifc.getMethod(methodName, parameterTypes);
				}
				catch (NoSuchMethodException ex) {
					// Alright, not on this interface then...
				}
			}
			// A final desperate attempt on the proxy class itself...
			return targetType.getMethod(methodName, parameterTypes);
		}
		catch (NoSuchMethodException ex) {
			throw new IllegalStateException(String.format(
					"Need to invoke method '%s' declared on target class '%s', " +
					"but not found in any interface(s) of the exposed proxy type. " +
					"Either pull the method up to an interface or switch to CGLIB " +
					"proxies by enforcing proxy-target-class mode in your configuration.",
					method.getName(), method.getDeclaringClass().getSimpleName()));
		}
	}

	@FunctionalInterface
	public interface MetadataLookup<T> {
		@Nullable
		T inspect(Method method);
	}

}

它的使用还是非常多得:

示例代码:

代码语言:javascript
复制
// 处理@EventListener注解
annotatedMethods = MethodIntrospector.selectMethods(targetType, 
	(MethodIntrospector.MetadataLookup<EventListener>) method -> AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));

// 处理@Scheduled和@Schedules注解
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
	(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
		Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);
SpringProperties

位于org.springframework.core包。我认为他是Spring给我们提供的一个便捷处理.properties文件的好帮手。

在classpath类路径下建一个文件:spring.properties(必须是类路径下,切必须叫这个文件名)

代码语言:javascript
复制
name=fangshixiang
代码语言:javascript
复制
    public static void main(String[] args) {
        String name = SpringProperties.getProperty("name");
        System.out.println(name); //fangshixiang
    }

就这样,非常简单的,就可议读出spring.properties这个配置文件里面指定key的值。这样若我们某些参数需要外部化配置,使用这个参数可谓是非常非常的方便啊。

application.properties这个配置文件尽量防止一些主线的配置文件,而spring.properties可议放置和容器无关、我们具体业务自己需要定义的配置(比如业务开关、业务时间等等)

它的源码也非常的简单,就是它在项目启动的时候会去类路径扫描名叫spring.properties,有就加载进来,没有就算了(就算我们没有此配置文件,也可以在一个地方set进去,再去另外一个地方get出来)。它提供如下四个方法:

代码语言:javascript
复制
	public static void setProperty(String key, @Nullable String value) {
		if (value != null) {
			localProperties.setProperty(key, value);
		}
		else {
			localProperties.remove(key);
		}
	}

	@Nullable
	public static String getProperty(String key) {
		String value = localProperties.getProperty(key);
		if (value == null) {
			try {
				value = System.getProperty(key);
			}
			catch (Throwable ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not retrieve system property '" + key + "': " + ex);
				}
			}
		}
		return value;
	}

	// 显然这两个事专门方便我们来处理开关得~~~~
	public static void setFlag(String key) {
		localProperties.put(key, Boolean.TRUE.toString());
	}
	public static boolean getFlag(String key) {
		return Boolean.parseBoolean(getProperty(key));
	}
SpringVersion、SpringBootVersion
代码语言:javascript
复制
    public static void main(String[] args) {
        // 貌似没有SpringCloudVersion
        System.out.println(SpringVersion.getVersion()); //4.3.23.RELEASE
        System.out.println(SpringBootVersion.getVersion()); //1.5.20.RELEASE
    }
Constants:常量获取工具

org.springframework.core包中,在处理类的常量的时候,我们可以借助它来处理~~。

它只有一个构造函数,传入一个Class,通过反射的方式获取目标source类中所有的public static final的常量放入一个Map中

常用的几个方法:通过asXX方法取出相应的值。

Demo如下:

代码语言:javascript
复制
public class Main {

    public static final int MAX_NUM = 5;
    public static final int MIN_NUM = 2;
    public static final String NAME = "fsx";
    public static final Map<String,Object> MAP = new HashMap<>();

    public static void main(String[] args) {
        Constants constants = new Constants(Main.class);
        System.out.println(constants.asNumber("MAX_NUM").intValue()); // 5
        System.out.println(constants.asString("NAME")); //fsx

        // 自动总个数
        System.out.println(constants.getSize()); //3

        //=============它的好处是提供一些批量获取的方法,在属性很多的时候  这个特别好用==============

        // 匹配前缀 批量获取 注意:此处返回的是字段名,不是值  不区分大小写  下同
        System.out.println(constants.getNames("M")); //[MIN_NUM, MAX_NUM, MAP]
        System.out.println(constants.getNames("m")); //[MIN_NUM, MAX_NUM, MAP]
        // 后缀匹配
        System.out.println(constants.getNamesForSuffix("NUM")); //[MIN_NUM, MAX_NUM]

        // 拿到所有的值  前缀匹配
        System.out.println(constants.getValues("M")); //[{}, 2, 5]
        // 后缀匹配
        System.out.println(constants.getValuesForSuffix("E")); //[fsx]
    }
}

注意:常量必须是 public static final 修饰的,否则使用asXX方法取出的时候抛exception

ObjectUtils

ObjectUtils工具类会尝试优雅的处理null输入,对于空输入通常不会抛出异常,每个方法都更详细的记录其行为。

另外它提供的方法:addObjectToArray()toObjectArray()isArray()arrayEquals()对处理数组都特别的好用

CollectionUtils(spring-core包的)

CollectionUtils真实项目中,是一个非常好用的工具类。

Apache commons collection4包下的CollectionUtils也很强大,可以结合来使用。 当然还有它的ListUtils、SetUtils、MapUtils等等都非常好用 参考:【小家java】Java之Apache Commons-Collections4使用精讲(Bag、Map、List、Set全覆盖)

未完,待续。。。
总结

本篇探讨了AOP的编程思想、过程,其主要思想是让开发者把诸多业务流程中的通用功能抽取出来,单独编写功能代码,形成独立的模块,这些模块也被称为切面。在业务流程执行过程中,Spring框架会根据业务流程要求,自动把切面切入到流程的合适位置

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年04月19日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Assert
  • ClassUtils:非常非常重要的一个工具类
  • Introspector:内省
  • MethodIntrospector
  • SpringProperties
  • SpringVersion、SpringBootVersion
  • Constants:常量获取工具
  • ObjectUtils
  • CollectionUtils(spring-core包的)
  • 未完,待续。。。
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档