什么是反射,反射有什么用,反射该怎么用?java
一些概念性的东西,这里就不细说了,下面主要给出一个很是简单的反射的调用工具类;spring
后续会提供一个基于Spring框架的反射工具类,主要用于反射代理bean对象,执行相关的方法apache
这样有什么好处?json
设想一下,你的工程运行在Spring框架上,你须要实时查看某些方法的返回结果的时候,能够怎么办?框架
在工程上开一个端口,接手外部传入的参数,利用反射去执行某些类的方法,并将结果打印出来,这样的工具是否是很赞?函数
反射相关的信息(类名,方法名,参数对象)---》 有了这些东西才能惟一的指定要执行的目的工具
传入给程序的是一个String类型的参数,对其进行解析,获取传说
传入给程序的是一个String类型的参数,对其进行解析,获取params对象; 还有一个方法则是对方法的参数进行解析测试
这里对于基本类型和封装类型的处理比较初级,能够尝试让二者能够兼容,灵活的处理一些方法优化
package com.mushroom.hui.common.invoke; import com.alibaba.fastjson.JSON; import org.apache.commons.lang.StringUtils; import org.springframework.util.CollectionUtils; import java.util.HashMap; import java.util.Map; /** * Created by hui on 16/4/10. */ public class ParamUtil { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ParamUtil.class); /** * 将传入的参数,转换为Params对象 * @param strPamras {"target":"invoke","class":"com.mushroom.hui.test.biz.Calculate","method":"add","parameter":"10"} * @return */ public static Params buildParams(String strPamras) { if (StringUtils.isBlank(strPamras)) { return null; } try { Map<String, String> map = JSON.parseObject(strPamras, Map.class); if (CollectionUtils.isEmpty(map)) { return null; } Params params = new Params(); params.setTarget(map.get("target")); params.setCls(map.get("class")); params.setMethod(map.get("method")); String args = map.get("params"); if (StringUtils.isBlank(args)) { return params; } Map<String, String> argMap = JSON.parseObject(args, Map.class); params.setParams(argMap); return params; }catch (Exception e) { logger.error("parse params to object error!"); logger.error("Exception: {}", e); return null; } } /** * 获取反射的方法对应参数信息 * @param params 传入的反射信息 * @param argTypes 参数类型 * @param argValues 参数value * @return true 表示解析成功; false 表示解析失败 */ public static boolean buildArgInfos(Params params, Class<?>[] argTypes, Object[] argValues) { Map<String, String> argus = params.getParams(); try { Class<?> clz; String value; int index = 0; for (Map.Entry<String, String> arg : argus.entrySet()) { clz = getBaseClass(arg.getKey()); argTypes[index] = clz; value = arg.getValue(); argValues[index++] = JSON.parseObject(value, clz); } return true; } catch (Exception e) { return false; } } private static Map<String, Class<?>> baseClass; static { baseClass = new HashMap<>(8); baseClass.put("short", short.class); baseClass.put("int", int.class); baseClass.put("long", long.class); baseClass.put("byte", byte.class); baseClass.put("float", float.class); baseClass.put("double", double.class); baseClass.put("boolean", boolean.class); baseClass.put("char", char.class); } private static Class<?> getBaseClass(String arg) throws ClassNotFoundException { if (StringUtils.isBlank(arg)) { return null; } if (baseClass.containsKey(arg)) { return baseClass.get(arg); } else { return Class.forName(arg); } } }
下面的代码有几个缺陷:ui
(add(int, int)与add(Integer, Integer) 被认为两个不一样的方法,其实通常也确实是两种不一样的方法,很明显的与咱们的认知是不同的)
package com.mushroom.hui.common.invoke; import java.lang.reflect.Method; /** * Created by hui on 16/4/10. */ public class InvokeUtil { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(InvokeUtil.class); public static Object invoke(String strParams) { Params params = ParamUtil.buildParams(strParams); if (params == null || ! params.isValiad()) { return null; } try { Class clz = Class.forName(params.getCls()); Object obj = clz.newInstance(); // 无参构造函数必需要有 int size = params.getParams().size(); if (size == 0) { // 没有参数 Method method = clz.getMethod(params.getMethod()); Object ans = method.invoke(obj); return ans; } Class<?>[] argTypes = new Class<?>[size]; Object[] argValues = new Object[size]; if (!ParamUtil.buildArgInfos(params, argTypes, argValues)) { return null; } Method method = clz.getMethod(params.getMethod(), argTypes); Object ans = method.invoke(obj, argValues); return ans; } catch (Exception e) { e.printStackTrace(); } return false; } }
package com.mushroom.hui.test.biz; import java.util.List; /** * Created by yihui on 16/4/10. */ public class Calculate { public int add(int num) { return num << 2; } public String array(List<String> list, int size) { String str = list.toString(); return str + " size: " + size; } } package com.mushroom.hui.test.invoke; import com.alibaba.fastjson.JSON; import com.mushroom.hui.common.invoke.InvokeUtil; import com.mushroom.hui.common.invoke.ParamUtil; import com.mushroom.hui.common.invoke.Params; import org.junit.Test; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by hui on 16/4/10. */ public class InvokeTest { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(InvokeTest.class); @Test public void invokeTest() { String clz = "com.mushroom.hui.test.biz.Calculate"; String mtd = "add"; try { Class cls = Class.forName(clz); Method[] methods = cls.getDeclaredMethods(); Method method = cls.getMethod(mtd, int.class); Object ans = method.invoke(cls.newInstance(), 20); logger.info("The ans is : {}", ans); } catch (Exception e) { e.printStackTrace(); logger.warn("e: {}", e); } } private String getAddArg() { Map<String, String> map = new HashMap<>(3); map.put("target", "invoke"); map.put("class", "com.mushroom.hui.test.biz.Calculate"); map.put("method", "add"); Map<String, String> args = new HashMap<>(); args.put("java.lang.Integer", "10"); map.put("params", JSON.toJSONString(args)); String strParams = JSON.toJSONString(map); System.out.println(strParams); return strParams; } private String getArrayArg() { Map<String, String> map = new HashMap<>(3); map.put("target", "invoke"); map.put("class", "com.mushroom.hui.test.biz.Calculate"); map.put("method", "array"); List<String> list = new ArrayList<>(); list.add("123"); list.add("hello"); list.add("world"); Map<String, String> args = new HashMap<>(); args.put("java.util.List", JSON.toJSONString(list)); args.put("int", "100"); map.put("params", JSON.toJSONString(args)); String strParams = JSON.toJSONString(map); System.out.println(strParams); return strParams; } @Test public void paramsTest() { // invoke Object obj = InvokeUtil.invoke(getAddArg()); System.out.println(obj); obj = InvokeUtil.invoke(getArrayArg()); System.out.println(obj); } }
上面贴出了代码,可是这些代码是干吗用的,为何要这么用,这样拥有什么好处呢,又能够用在什么地方呢
从上面的代码出发,一个一个分析
Params类中存储了一些有意思的东西,咱们主要的聚焦点放在 cls,method和params上,这三个也是咱们必须的参数
com.mushroom.hui.test.biz.Calculate
, 全路径的类名有上面的三个东西,就能够利用jdk的放射相关类来完成调用,大体的流程是:
其实经过上面的说明,咱们也就知道实现反射的大体流程了,util类则只是一个工具类,将String封装为上面的Params对象,解析参数的类型和value
咱们设定的传入字符串形式的参数,其格式为:
{ "target": "invoke", "class": "com.mushroom.hui.test.biz.Calculate", "method": "array", "params": { "int": "100", "java.util.List": [ "123", "hello", "world" ] } }
从json字符串反序列化,从上面的结构中能够很容易的建立一个Parmas对象,对此咱们能够很容易的get到 class, method
而对于方法的参数 params,则稍稍有点特殊
由于在具体的肯定Method对象的时候,咱们须要知道参数的类型;而在执行方法的时候,咱们则是须要参数的value
所以,咱们须要从上面的json串中得到 参数类型列表 & 参数value列表
也就是com.mushroom.hui.common.invoke.ParamUtil#buildArgInfos
的目的,具体怎么玩的能够看上面的代码
须要注意的一点是基本类型和封装类型之间是有区别的,特别是在获取Method对象的时候
todo:如何优化一下基本类型和封装类型,保证二者最终的效果一致?
这个类的做用其实很清晰了,传入参数,返回反射调用的结果,基本流程就是上面列的:
注意一下没有参数和有参数是区分开来的,why?
上面三个类完成了一个简单的反射工具,那么如何进行测试呢?
首先是构造一个参数,而后调用 InvokeUtil的方法便可,这里没什么技术点,就很少说了
框架层面对于反射用的比较多,这个就很少说了;咱们接下来给一个简单的应用场景
假设你有一个java应用,对外提供rpc接口,假设如今某一个接口返回的数据不对了,那么你能够怎么办,远程debug(线程阻塞,会被打死的)
用反射就是一个思路,开一个端口,接受请求,将要执行的对象的方法和参数丢进去,查看输出结果,这样就不会局限于rpc接口的调用了,能够愉快的调用各类内部接口了
spring框架是有一个beanFactory, 能够用这个东西来建立一个bean对象,此外就是可否反射执行一个私有的方法
参数的指定可否更加灵活一些呢?