Java反射————Method根据方法名称字符串调用方法

引言

之前浏览廖雪峰老师的个人博客网站,无意间发现了关于在Java8中获取参数的方法,随手一转《Java 8中获取参数名称》,没想到今天遇到一个功能,非常符合这种反射调用的使用场景。回看了这篇之前转载的文章,然后根据自己的理解完成了这个功能。

场景描述

功能其实并不复杂。一个设备表中有两个字段,A和B,希望既可以通过A来查找相应记录,又能够通过B来查找相应记录,但问题就在于A和B的样子非常相似,不仅类型相同,就连名字也几乎完全一样(lntDeviceType和ytDeviceType)。

我在Repository中定义了两个方法,分别区分开不同设备类型的查询:

public DeviceType findByYtDeviceType(String ytDeviceType);
public DeviceType findByLntDeviceType(String lntDeviceType);

可是如何在Service中区分应该调用哪个方法呢?第一个能想到的方法就是写死,通过一个值来区分是根据A字段来查询还是B字段来查询,像如下这种形式:

public DeviceType findDeviceType(String column, String deviceTypeStr) {
    if(column.equals("yt")) {
	return findByYtDeviceType(deviceTypeStr);
    } else if (column.equals("lnt")) {
	return findByLntDeviceType(deviceTypeStr);
    } else {
        return null;
    }
}

上述代码,通过一个colum字符串来得知究竟是通过ytDeviceType字段来查询,还是通过lntDeviceType来查询。问题可以得到解决,但是如果增加了一个C字段怎么办?又增加了一个D字段呢?难道每加一个字段都要加一个else if 写死一个分支?

解决办法——反射调用

思考过后,我想到了通过反射的方式来实现这个功能:

public DeviceType findByDeviceType(String deviceTypeTitle, String deviceType) {
	// 校验deviceTypeTitle是否正确
	try {
		Set<String> deviceTypeColumSet = mapper.convertValue(new DeviceType(), Map.class).keySet();
		if (!deviceTypeColumSet.contains(deviceTypeTitle))
			return null;

		String findBy = "findBy";
		// 根据deviceTypeTitle查找对应方法名并调用方法
		Method findByXxDeviceType = dtRepo.getClass().getMethod(findBy + StringUtils.capitalize(deviceTypeTitle),
				String.class);
		DeviceType deviceTypeBean = (DeviceType) findByXxDeviceType.invoke(dtRepo, deviceType);
		logger.info("按类型查找设备类型deviceTypeTitle = " + deviceTypeTitle + "; deviceType = " + deviceType);
		return deviceTypeBean;
	} catch (Exception e) {
		e.printStackTrace();
	}

	return null;
}

说明:try块的前三行代码主要是验证deviceTypeTitle是否在DeviceType类型的属性之列,比如DeviceType有A、B两个属性,那么如果deviceTypeTitle是A或者B就符合要求,如果是C就不可以了。StringUtils.capitalize方法主要是将deviceTypeTitle的首字母变为大写,然后加上前缀 “findBy” 从而得到Repository中的方法名

因为不论是用哪个字段来查询,其方法名始终都是  “findByXxxx” ,那何不通过映射自动匹配到对应的方法然后调用呢?这个时候我突然回想起了之前转载的廖雪峰老师的博客《Java 8中获取参数名称》,简单回看之后果然可以解决我的问题,再进一步搜索相关资料之后完成了上述代码。

可以看到我通过拼接一个“findBy”前缀,然后将传入的 deviceTypeTitle 首字母大写与前缀拼接后即可得到Repository中对应的方法名,然后我通过方法名即可进行调用,完全不需要担心未来扩展的问题。即便未来扩展新的设备类型字段,而只需要在Repository中按照 “findByXxxx” 命名规则新加一个查询即可,service中的分发请求完全不需要改动,岂不美哉?!

综上,就是关于通过方法名称字符串映射调用方法的例子,希望能够对大家有所帮助,欢迎文末留言。

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页