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;
}
}
发表回复