前言:前段时间在设计公司基于netty的易用框架时,很多地方都用到了反射机制。反射的性能一直是大家有目共睹的诟病,相比于直接调用速度上差了很多。但是在很多地方,作为未知通用判断的时候,不得不调用反射类型来保障代码的复用性和框架的扩展性。所以我们只能想办法优化反射,而不能抵制反射,那么优化方案,这里给大家推荐了ReflectASM。

一、性能对比

我们先通过简单的代码来看看,各种调用方式之间的性能差距。

public static void main(String[] args) throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-common.xml"});
new InitMothods().initApplicationContext(ac); long now;
HttpRouteClassAndMethod route = InitMothods.getTaskHandler("GET:/login/getSession");
Map map = new HashMap(); //-----------------------最粗暴的直接调用 now = System.currentTimeMillis(); for(int i = 0; i<5000000; ++i){
new LoginController().getSession(map);
}
System.out.println("get耗时"+(System.currentTimeMillis() - now) + "ms); //---------------------常规的invoke now = System.currentTimeMillis(); for(int i = 0; i<5000000; ++i){
Class<?> c = Class.forName("com.business.controller.LoginController"); Method m = c.getMethod("getSession",Map.class);
m.invoke(SpringApplicationContextHolder.getSpringBeanForClass(route.getClazz()), map);
}
System.out.println("标准反射耗时"+(System.currentTimeMillis() - now) + "ms); //---------------------缓存class的invoke now = System.currentTimeMillis(); for(int i = 0; i<5000000; ++i){
try {
route.getMethod().invoke(SpringApplicationContextHolder.getSpringBeanForClass(route.getClazz()),
new Object[]{map});
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
} System.out.println("缓存反射耗时"+(System.currentTimeMillis() - now) + "ms秒); //---------------------reflectasm的invoke MethodAccess ma = MethodAccess.get(route.getClazz());
int index = ma.getIndex("getSession");
now = System.currentTimeMillis(); for(int i = 0; i<5000000; ++i){
ma.invoke(SpringApplicationContextHolder.getSpringBeanForClass(route.getClazz()), index, map);
}
System.out.println("reflectasm反射耗时"+(System.currentTimeMillis() - now) + "ms); }

每种方式执行500W次运行结果如下:

  • get耗时21ms
  • 标准反射耗时5397ms
  • 缓存反射耗时315ms
  • reflectasm反射耗时275ms

(时间长度请忽略,因为每个人的代码业务不一致,主要看体现的差距,多次运行效果基本一致。)

结论:方法直接调用属于最快的方法,其次是java最基本的反射,而反射中又分是否缓存class两种,由结果得出其实反射中很大一部分时间是在查找class,实际invoke效率还是不错的。而reflectasm反射效率要在java传统的反射之上快了接近1/3.

二、reflectasm原理解析。

ReflectASM是一个很小的java类库,主要是通过asm生产类来实现java反射。他的主要代码还是get方法,但是由于get方法源码比较多,就不在博客中贴出来了,大家可以自己点进去看。这里我们给出实现invoke的抽象方法。

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) package com.johhny.ra; import com.esotericsoftware.reflectasm.MethodAccess; // Referenced classes of package com.johhny.ra:
// User public class UserMethodAccess extends MethodAccess
{ public UserMethodAccess()
{
} /**
* 这个方法是主要是实现了MethodAccess 的抽象方法,来实现反射的功能
* @param obj 需要反射的对象
* @param i class.getDeclaredMethods 对应方法的index
* @param 参数对象集合
* @return
*/
public transient Object invoke(Object obj, int i, Object aobj[])
{
User user = (User)obj;
switch(i)
{
case 0: // '\0'
return user.getName(); case 1: // '\001'
return Integer.valueOf(user.getId()); case 2: // '\002'
user.setName((String)aobj[0]);
return null; case 3: // '\003'
user.setId(((Integer)aobj[0]).intValue());
return null;
}
throw new IllegalArgumentException((new StringBuilder("Method not found: ")).append(i).toString());
}
}

由代码可以看出来,实际上ReflectASM就是把类的各个方法缓存起来,然后通过case选择,直接调用,因此速度会快上很多。但是它的get方法同样会消耗很大的时间,因此就算是使用ReflectASM的朋友也记得请在启动的时候就初始化get方法计入缓存。

ReflectASM-invoke,高效率java反射机制原理的更多相关文章

  1. [转]Java反射机制详解

    目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ·获取一个对象的父类与实现的接口 ·获取某个类中的全部构造函数 - 详 ...

  2. 【转载】Java反射机制详解

    转自:http://baike.xsoftlab.net/view/209.html#3_8 1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对 ...

  3. Java 基础之详解 Java 反射机制

    一.什么是 Java 的反射机制?   反射(Reflection)是Java的高级特性之一,是框架实现的基础,定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: ...

  4. java反射机制详解 及 Method.invoke解释

    JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为ja ...

  5. java反射机制 + Method.invoke解释 getMethod + 反射理解

    功能: 通过读取另一个Dll去创建一个控件(Form,Button,TextBox,DataGridView),然后对当中一些属性进行检查. 创建控件的大致流程是,Assembly->Modul ...

  6. Java反射机制剖析(四)-深度剖析动态代理原理及总结

    动态代理类原理(示例代码参见java反射机制剖析(三)) a)  理解上面的动态代理示例流程 a)  理解上面的动态代理示例流程 b)  代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...

  7. Java反射机制及Method.invoke详解

    JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为ja ...

  8. 浅析Java中的反射机制原理

    反射反射,程序员的快乐! Java中反射机制使用的还是比较广泛的,系统的灵活性.可扩展性大都都是通过反射等方式来加载外部插件,使得系统与插件解耦的同时,增加了功能.但是很多人都只是会用,却是不知道它的 ...

  9. Java反射机制专题

    ·Java Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方 ...

随机推荐

  1. PHP_保留两位小数并且四舍五入_保留两位小数并且不四舍五入

    php保留两位小数并且四舍五入 $num = 123213.666666; echo sprintf("%.2f", $num); php保留两位小数并且不四舍五入 php进一法取 ...

  2. R语言︱数据分组统计函数族——apply族用法与心得

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 笔者寄语:apply族功能强大,实用,可以代替 ...

  3. hi3531 SDK 编译 uboot, 修改PHY地址, 修改 uboot 参数 .

    一,编译uboot SDK文档写得比较清楚了,写一下需要注意的地方吧. 1. 之前用SDK里和别人给的已经编译好的uboot,使用fastboot工具都刷不到板子上.最后自己用SDK里uboot源码编 ...

  4. Jquery+Json+Handler文件结合应用实例

    1.页面script代码-[model数据.字符串] <script type="text/javascript" charset="utf-8" src ...

  5. Docker 小记 — Compose & Swarm

    前言 任何相对完整的应用服务都不可能是由单一的程序来完成支持,计划使用 Docker 来部署的服务更是如此.大型服务需要进行拆分,形成微服务集群方能增强其稳定性和可维护性.本篇随笔将对 Docker ...

  6. SPOJ D-QUERY

    以前主席树学  kungbin 最近看了网上的版本 终于发现和我以前学的线段树差不多的了 希望最近能够加强 #include<bits/stdc++.h> using namespace ...

  7. box-sizing -- 盒模型

    项目开发中,在浏览同事的代码,发现他经常用一个属性--box-sizing,很好奇是什么,于是乎,上网查阅资料学了起来. 首先我们先复习一下盒模型的组成:一个div通常由 content(内容)+ma ...

  8. [HDU5663]Hillan and the girl

    题面戳我(题面很鬼畜建议阅读一下) 题意:给出n,m,求 \[\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)\mbox{不是完全平方数}]\] 多组数据,\(n,m\le1 ...

  9. 【linux之进程管理,系统监控】

    一.进程管理 前台进程:一般是指占据着标准输入和/或标准输出的进程后台进程:不占据默认开启的进程都是前台进程ctrl+C 中断ctrl+z 从前台转入后台bg 后台进程编号 让其在后台运行ls -R ...

  10. 前端综合学习笔记---异步、ES6/7、Module、Promise同步 vs 异步

    同步 vs 异步 先看下面的 demo,根据程序阅读起来表达的意思,应该是先打印100,1秒钟之后打印200,最后打印300.但是实际运行根本不是那么回事 console.log(100) setTi ...