需要用到的工具  jdk : javac javap

class 反编译 :JD-GUI http://jd.benow.ca/

先来看下jdk动态代理跟native性能比较

 package com.eyu.onequeue;

 import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class TestProxy {
public interface UserService {
public String getName(int id); public Integer getAge(int id);
} public static class UserServiceImpl implements UserService { @Override
public String getName(int id) {
return "name : " + id;
} @Override
public Integer getAge(int id) {
return id;
}
}; public static void main(String[] args) {
testNative();
testJdk();
} public static void testJdk() {
UserService impTarget = new UserServiceImpl();
// 代理处理逻辑
InvocationHandler handler = new InvocationHandler() { @Override
public Object invoke(Object target, Method method, Object[] args) throws Throwable {
return method.invoke(impTarget, args);
}
};
// Proxy.newProxyInstance(ClassLoader/**ClassLoader 没有特别处理 拿默认即可 **/,
// Class<?>[]/**代理接口类**/, InvocationHandler /**代理处理逻辑**/)
UserService proxy = (UserService) Proxy.newProxyInstance(TestProxy.class.getClassLoader(), new Class[] { UserService.class }, handler); run("jdk", proxy);
} public static void testNative() {
UserService impTarget = new UserServiceImpl();
run("native", impTarget);
} private static void run(String tag, UserService impTarget) {
int c = 15;
System.out.println();
while (c-- > 0) {
long start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
impTarget.getName(11);
}
long end = System.currentTimeMillis();
System.out.print(tag + ": " + (end - start) + " ");
}
}
}

运行结果:

native: 175 native: 182 native: 126 native: 172 native: 126 native: 127 native: 127 native: 126 native: 127 native: 126 native: 126 native: 128 native: 126 native: 127 native: 126
jdk: 214 jdk: 170 jdk: 169 jdk: 169 jdk: 170 jdk: 170 jdk: 170 jdk: 170 jdk: 170 jdk: 172 jdk: 169 jdk: 172 jdk: 169 jdk: 171 jdk: 169

先运行预热,看出执行五次之后比较稳定

jdk动态代理使用非常简单,使用Proxy.newProxyInstance 静态方法即可

接下来我们看下class指令

javac -encoding UTF-8 -d . TestProxy.java

javap -v com\eyu\onequeue\TestProxy.class > s.txt

其中

// Method java/lang/reflect/Proxy.newProxyInstance:(Ljava/lang/ClassLoader;[Ljava/lang/Class;Ljava/lang/reflect/InvocationHandler;)Ljava/lang/Object;

没有详细看到代理类指令

运行时生成的动态代理对象是可以导出到文件的,方法有两种

  1. 在代码中加入System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
  2. 在运行时加入jvm 参数 -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

我们在main方法加一行System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 然后执行一下

  public static void main(String[] args) {
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//省略
}

这时在包下会多出$Proxy0.class文件

proxy0.class用jd-gui打开

 package com.sun.proxy;

 import com.eyu.onequeue.TestProxy.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0
extends Proxy
implements TestProxy.UserService
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
} public final boolean equals(Object paramObject)
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} public final String toString()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} public final String getName(int paramInt)
{
try
{
return (String)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} public final Integer getAge(int paramInt)
{
try
{
return (Integer)this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
} static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.eyu.onequeue.TestProxy$UserService").getMethod("getName", new Class[] { Integer.TYPE });
m4 = Class.forName("com.eyu.onequeue.TestProxy$UserService").getMethod("getAge", new Class[] { Integer.TYPE });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}

proxy0

proxy0分析分两部份

1.在内存动态生成代理类 以$proxy 开头

$Proxy0 extends Proxy implements XXXXProxy.UserService

并初始化InvocationHandler 同绑定 Method

 public $Proxy0(InvocationHandler paramInvocationHandler)
{
  super(paramInvocationHandler);
} static
{
try
{
  m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
  m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  m3 = Class.forName("com.eyu.onequeue.TestProxy$UserService").getMethod("getName", new Class[] { Integer.TYPE });
  m4 = Class.forName("com.eyu.onequeue.TestProxy$UserService").getMethod("getAge", new Class[] { Integer.TYPE });
  m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  return;
}
.....
}

第二部分:代理原对象所有方法实现调用InvocationHandler 类的 Object invoke(Object target, Method method, Object[] args) throws Throwable 方法 再通过method反射invoke

public final String getName(int paramInt)
{
try
{
return (String)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

我们通过生成指令 E:\java\findme\com\sun\proxy>javap -v $Proxy0.class > d.txt

来查看代理过的getName方法共多少条指令

  public final java.lang.String getName(int) throws ;
descriptor: (I)Ljava/lang/String;
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=10, locals=3, args_size=2
0: aload_0
1: getfield #16 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
4: aload_0
5: getstatic #57 // Field m3:Ljava/lang/reflect/Method;
8: iconst_1
9: anewarray #22 // class java/lang/Object
12: dup
13: iconst_0
14: iload_1
15: invokestatic #63 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
18: aastore
19: invokeinterface #28, 4 // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
24: checkcast #52 // class java/lang/String
27: areturn
28: athrow
29: astore_2
30: new #42 // class java/lang/reflect/UndeclaredThrowableException
33: dup
34: aload_2
35: invokespecial #45 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
38: athrow
Exception table:
from to target type
0 28 28 Class java/lang/Error
0 28 28 Class java/lang/RuntimeException
0 28 29 Class java/lang/Throwable
Exceptions:
throws

如果不出错,到 27:areturn  至少要执行到13条指令 java8对动态代理有优化过

结论是:jdk动态代理比原生调用只慢几十毫秒,这点可以忽略不计

[编织消息框架][JAVA核心技术]jdk动态代理的更多相关文章

  1. [编织消息框架][JAVA核心技术]cglib动态代理

    先在mavne项目里添加cglib库 maven仓库搜索cglib版本 maven地址:http://mvnrepository.com/ 点击最新的版本 3.2.5 复制到pom.xml  depe ...

  2. [编织消息框架][JAVA核心技术]异常应用

    QException是项目业务异常基类 按模块划分子类异常,方便定位那块出错 有个来源码属性code作用定位某个功能处理出错逻辑,数字类型节省内存空间,同时减少创建子类的子类 QSocketExcep ...

  3. [编织消息框架][JAVA核心技术]动态代理介绍

    由于java是种强类型静态语言,在执行时无法动态生成代码,静态语言基本都有这特性 动态生成代码有几种好处,也是弱类型语言的优点 1.部份逻辑可以实现热更新 2.远程调用实现非常适合 3.能动态生成扩展 ...

  4. [编织消息框架][JAVA核心技术]动态代理应用12-总结

    动态代理这篇比较长,是框架组成的重要基础 回顾下学到的应用技术 1.异常应用 2.annotation技术 3.数值与逻辑分享 4.jdk.cglib.javassist等动态代理技术 5.懒处理.预 ...

  5. [编织消息框架][JAVA核心技术]annotation基础

    应用动态代理技术要先掌握annotation技术 注解是JDK1.5之后才有的新特性,JDK1.5之后内部提供的三个注解 @Deprecated 意思是“废弃的,过时的” @Override 意思是“ ...

  6. [编织消息框架][JAVA核心技术]动态代理应用4

    基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...

  7. [编织消息框架][JAVA核心技术]动态代理应用5-javassist

    基础部份: 修改class我们用到javassist,在pom.xml添加 <properties> <javassist.version>3.18.2-GA</java ...

  8. [编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现

    private static Map<Short, Map<Byte, Method>> RECEIVE_METHOD_INFO = new HashMap<>() ...

  9. [编织消息框架][JAVA核心技术]动态代理应用7-IRpcSend实现

    根据设计生成两个接口,IRpcSend send方法返回数据要求包装成QResult对象 public interface IRpcSend { public <T> QResult< ...

随机推荐

  1. UI进阶 即时通讯之XMPP登录、注册

    1.XMPP环境搭建 http://www.cnblogs.com/fearlessyyp/p/5506644.html 第一次打开可能会有点儿慢,图片很多,步骤很详细,祝搭建成功. 2.工程中添加X ...

  2. Swift 面向对象解析(一)

    面向对象总体概括: Swift 不仅能够面向过程编程,也能够面向对象编程(OOP).面向对象其实就是“以对象为核心”,把我们的客观世界想着是由一个个对象组成的,面向对象编程则为对象提供了属性和方法,属 ...

  3. IP地址和硬件地址 ARP协议

    ip地址使用在网络层以上,是一个逻辑地址,物理地址是数据链路层和物理层使用的 在发送数据的时候,数据是从上层往下层发送的,通过tcp报文->ip数据报->mac数据帧 IP地址放在数据报的 ...

  4. c++编程思想(一)--对象导言

    回过头来看c++编程思想第一章,虽然只是对c++知识的一个总结,并没有实质性知识点,但是收获还是蛮多的! 下面感觉是让自己茅塞顿开的说法,虽然含义并不是很准确,但是很形象(自己的语言): 1.类描述了 ...

  5. devexpress设置皮肤、字体以及折叠菜单、伸缩Panel的实现

    1.为了体现系统的个性化,越来越多的系统增加了换肤功能.这里例举一个devexpress实现换肤的案例,效果图对比: 第二张图片中更换了皮肤与字体. 2.皮肤数据源绑定代码: //循环添加皮肤名称 f ...

  6. BZOJ 3652: 大新闻(数位DP+概率论)

    不得不说数位DP和博弈论根本不熟啊QAQ,首先这道题嘛~~~可以分成两个子问题: 有加密:直接算出0~n中二进制每一位为0或为1分别有多少个,然后分位累加求和就行了= = 无加密:分别算出0~n中二进 ...

  7. 使用git恢复未提交的误删数据

    不小心将项目中一个文件夹删除还未提交,或者已经提交, 此时想要恢复数据该怎么办? 答案是git reflog,使用git reflog命令可以帮助恢复git误操作,进行数据恢复. 操作过程: 打开终端 ...

  8. Javascript正则表达式(上)

    正则表达式一般用于验证客户端的用户输入,而服务器端的PHP.ASP.NET等脚本无须再进行验证,节约了后台开销. 1.两种创建方法 var box=new RegExp("Box" ...

  9. thinkcmf,thinkphp,表格导入(PHPexcel)的实现,新手向

    对于新手来说,可以把表格中的数据导入进数据库那是十分好玩的一件事,我自己实现了一下网上的写法,基于PHPexcel实现的表格导入,踩了2个小时的坑,最终实例! 因为在thinkcmf中自己添加了php ...

  10. java里Struts2学习登录练习详解

    最近在学struts2里面遇到很多错误,今天跟大家分享一下,我的开发工具是Eclipse: 1.到网上下载Struts2的包,这里不再累赘,百度有很多: 2.新建一个项目,记得后面加上web.xml文 ...