spring反射调用 及java MethodHandle反射

java反射

其实spring 也是在java 反射上封装了一层调用而已,
基本的java 反射如下:
invoke 里面第一个参数传null 表示反射调用静态的方法

try {
            Class json = Class.forName("cn.jia.service.utils.JacksonUtils");
            Object object = json.newInstance();
            Method method = json.getMethod("obj2str", Object.class);
            Jo jo = new Jo("wo", "cao");
            Object re = method.invoke(null, jo);
            System.out.println(re);
        }  catch (Exception e) {
            e.printStackTrace();
        }

反射优化

https://www.jianshu.com/p/3b311109050b

$$使用methodAccessor 来做具体调用, methodaccessor 有native版,开始使用nactive 版,调用的native 的invoke0, 当native调用次数变多后,生成一个 java版的methodAccessor、使用asm 生成的,后面就类似调用java代码一样来,直接方法调用.$$

Class.forName 会调用本地方法(Java和C++的相互转换,非常耗时),Class.getMethod 则会遍历该类的公有方法。如果没有匹配到,它还将遍历父类的公有方法, invoke 还检查方法权限,获取方法 Method 对象,返回方法的拷贝

java7 后的MethodHandle

https://juejin.cn/post/6844904177131323406
MethodHandle 可以看作是方法的指针,MethodType 是方法返回值和入参的类型.
主要方法就是MethodHandles.lookup.find 方法 , findVirtual 是普通方法, findStatic是静态方法.

             Class json = Class.forName("cn.jia.service.utils.JacksonUtils");
            MethodType methodType = MethodType.methodType(String.class,Object.class);
            MethodHandle methodHandle = MethodHandles.lookup().findStatic(json, "obj2str", methodType);
            Object result = methodHandle.invoke(jo);
            System.out.println(result);

https://zhuanlan.zhihu.com/p/28124632

methodHandle 比以前的java 反射要快了点

invoke0 源码阅读

源代码来源:
https://blog.csdn.net/wenyuan65/article/details/81145900
https://blog.csdn.net/qq_31865983/article/details/102877069

从java 的navtive 的 invoke0 到 JVM_InvokeMethod 到 Reflection::invoke_method 到 Reflection::invoke到 JavaCalls::call(&result, method, &java_args, THREAD);

上面这个流程里面就很简单了.
1. 检查一下访问权限,
2. 构造method: 是通过动态链接上的获取, method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD);
4. 把java 类型转成c++类型 java_args,然后构造JacaCalls 的入参,
5. 调用JavaCalls::call就行了.
最后就是这个JacvaCalls:: call了 这个就是java 调用方法的具体实现,例如方法a调用方法b,就是编译的时候 invokeVirtual,里面的指令就是翻译成JavaCall,

所以从这里能看出反射最后就是一个普通的方法调用,只是method是动态链接了,参数是序列化了.

基于asm的反射优化

在native方法调用次数大于一个值(15)后,jvm就把这个调用改成asm生成的代码调用了,这样就只在java中跑,没有把参数啥的转到c++环境,其实性能都是耗在这种运行环境切换上了. asm动态生成字节码后直接调用,

spring 反射

主要的代码就是下面, 使用的是getBean 获取spring 管理的bean, method 获取也是用的spring的方法, 我们获取了object和 method 就可以简单的调用 invoke了.

            Class beanClass = Class.forName(beanName);
            Object object = applicationContext.getBean(beanClass);
            Method method = ReflectionUtils.findMethod(object.getClass(),methodName, argClass);
            method.invoke(object, argObject);

但是其实很多基于spring的组件都是让我们实现一下接口,因为 使用spring
getBean 后, 强转接口,直接调用,这样就没有反射,而且还很简单了,入参啥的都确定了.


// 本地使用 public Object getBeanCall(String beanName, String methodName, String argClassName, String arg, String contex) { try { Class beanClass = Class.forName(beanName); Object object = applicationContext.getBean(beanClass); String[] argStringClass = argClassName.split(";"); Class[] argClass = new Class[argStringClass.length]; for (int i = 0; i < argStringClass.length; i++) { argClass[i] = Class.forName(argStringClass[i]); } Method method = ReflectionUtils.findMethod(object.getClass(), methodName, argClass); try { // arg 序列化 String[] argStr = arg.split(";"); if (argStr.length != argClass.length) { logger.error("arg is not belong to the argClass"); return null; } Object[] argObject = new Object[argStr.length]; for (int i = 0; i < argStr.length; i++) { if (argClass[i].getName().indexOf("java.lang") > -1) { argObject[i] = JacksonUtil.str2base(argStr[i], argClass[i]); } else { argObject[i] = JacksonUtil.str2objByType(argStr[i], argClass[i]); } System.out.println(argObject[i]); } return method.invoke(object, argObject); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (Exception e) { System.out.println(e); } return null; } public class JacksonUtil { private static ObjectMapper mapper = new ObjectMapper(); static { //mapper.configure() } public static <T> T str2obj(String str, Class<T> tClass) throws JsonProcessingException { return mapper.readValue(str, tClass); } public static <T> T str2objByType(String str, Class tClass) throws JsonProcessingException { return (T) mapper.readValue(str, tClass); } public static <T> T obj2objByType(Object o,Class tClass){ return (T) mapper.convertValue(o,tClass); } @SneakyThrows public static <T> String obj2str(T t) { return mapper.writeValueAsString(t); } public static <T> T str2base(String str, Class<T> type) { String classSimpleName = type.getSimpleName(); if (type == String.class) { return (T) str; } if (type == Integer.class) { classSimpleName = "Int"; } String convertMethodName = "parse" + classSimpleName; try { Method m = type.getMethod(convertMethodName, String.class); return (T) m.invoke(null, str); } catch (Exception e) { e.printStackTrace(); } return null; } }

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注