Spring中的BeanUtils藏着什么奥秘?


最近,博主在实习时候碰到了一个很好用的东西,就是BeanUtils.copyPropertis(object,object),这个方法非常的方便,例如

public class Task {
    private String taskPerson;
    private String taskName;
    private Integer taskId;
    private String taskTopic;
}

这样一个类,如果只有其中的name和topic那么让你复制到另一个业务对象中,则需要2次的get,set调用,但是BeanUtils.copyPropertis直接复制对应的参数到目标object。所以让我们来看看这个工具类还有什么好东西吧。

类介绍

  • Static convenience methods for JavaBeans: for instantiating beans,
    checking bean property types, copying bean properties, etc.
    Mainly for use within the framework, but to some degree also
    useful for application classes.

简单来说,这个类是主要是为了框架使用的便捷,同时也可以适用于一些应用场景

类结构

类结构图

方法分析

instantiate 等方法

这个是此类的结构图,我们先看下前4个方法

public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
		Assert.notNull(clazz, "Class must not be null");
		if (clazz.isInterface()) {
			throw new BeanInstantiationException(clazz, "Specified class is an interface");
		}
		try {
			return clazz.newInstance();
		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(clazz, "Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(clazz, "Is the constructor accessible?", ex);
		}
	}

首先这几个类的目的就是创建一个类实例,传入一个类类型,判断是否为接口,然后再通过calss的newInstance动态的创建实例 newInstance 方法和 new 关键字的不同是newInstance可以在运行时动态创建实例,而且是无参的构造方法,new创建实例必须类已经被加载和确定,可以是有参的。这个是第一个方法。如果要区分不同的话,

  • instantiate(Class clazz) 是通过反射生成一个的类实例
  • instantiateClass(Class clazz) 是通过无参构造器生成类实例
  • instantiateClass(Class<?> clazz, Class assignableTo) 生成一个类实例转换成指定的类
  • nstantiateClass(Constructor ctor, Object… args) 通过给定的构造器生成类实例 可以有参可以无参

findMethod系列方法

public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
		try {
			return clazz.getMethod(methodName, paramTypes);
		}
		catch (NoSuchMethodException ex) {
			return findDeclaredMethod(clazz, methodName, paramTypes);
		}
	}

这个方法也没什么好说的就是调用class类的底层方法getMethod()通过方法名和参数获取指定的方法,如果获取不到就调用此类的 findDeclaredMethod 也就是

public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
		try {
			return clazz.getDeclaredMethod(methodName, paramTypes);
		}
		catch (NoSuchMethodException ex) {
			if (clazz.getSuperclass() != null) {
				return findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes);
			}
			return null;
		}
	}

重点是class的getDeclareMethod方法

 @CallerSensitive
    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
        if (method == null) {
            throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
        }
        return method;
    }

通过搜索获取类声明的所有方法包括了private的方法 让我们再回到之前如果本类实在没有方法,我也求求你了我真的没有啊! 好的,那如果你有爸爸也就是父类我们就去父类里面找,来个大搜查

		if (clazz.getSuperclass() != null) {
				return findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes);

实在找不到就返回null了

findMethodWithMinimalParameters

public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName)
			throws IllegalArgumentException {

		Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);
		if (targetMethod == null) {
			targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);
		}
		return targetMethod;
	}

这个方法也很类似,就是通过传入一个类来找到类中对应方法名参数最少的方法,当然最好是那种一个都没有的无参的方法,如果能直接通过遍历的查找获得那最好,如果没有就查找所有声明的方法包括private的方法。下面两个方法也就不贴代码了

resolveSignature

public static Method resolveSignature(String signature, Class<?> clazz) {
		Assert.hasText(signature, "'signature' must not be empty");
		Assert.notNull(clazz, "Class must not be null");
		int firstParen = signature.indexOf("(");
		int lastParen = signature.indexOf(")");
		if (firstParen > -1 && lastParen == -1) {
			throw new IllegalArgumentException("Invalid method signature '" + signature +
					"': expected closing ')' for args list");
		}
		else if (lastParen > -1 && firstParen == -1) {
			throw new IllegalArgumentException("Invalid method signature '" + signature +
					"': expected opening '(' for args list");
		}
		else if (firstParen == -1 && lastParen == -1) {
			return findMethodWithMinimalParameters(clazz, signature);
		}
		else {
			String methodName = signature.substring(0, firstParen);
			String[] parameterTypeNames =
					StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen));
			Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
			for (int i = 0; i < parameterTypeNames.length; i++) {
				String parameterTypeName = parameterTypeNames[i].trim();
				try {
					parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());
				}
				catch (Throwable ex) {
					throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" +
							parameterTypeName + "] for argument " + i + ". Root cause: " + ex);
				}
			}
			return findMethod(clazz, methodName, parameterTypes);
		}
	}

本方法也就是通过方法签名来对类中的方法进行获取,关于方法签名的知识这里就先不介绍了,方法签名中的()中包含了方法的参数类,

  • 当两者都不存在的时候就只是方法名 直接调用先前的方法获取最小参数的类方法
  • 当都存在时候对参数进行获取再组装好调用findMethod方法。
  • 其他情况为异常报错
发布了29 篇原创文章 · 获赞 19 · 访问量 6514

猜你喜欢

转载自blog.csdn.net/wenzhouxiaomayi77/article/details/95451760