Dubbo源码分析(八):Javassist字节码技术生成代理

Java动态编程的作用:

     通过配置生成代码,减少重复编码和维护成本

我们常用到的动态特性主要是反射,在运行时查找对象属性、方法,修改作用域,通过方法名称调用方法等。在线的应用不会频繁使用反射,因为反射的性能开销较大。其实还有一种和反射一样强大的特性,但是开销却很低,它就是Javassit。

Javassit其实就是一个二方包,提供了运行时操作Java字节码的方法大家都知道,Java代码编译完会生成.class文件,就是一堆字节码。JVM(准确说是JIT)会解释执行这些字节码(转换为机器码并执行),由于字节码的解释执行是在运行时进行的,那我们能否手工编写字节码,再由JVM执行呢?答案是肯定的,而Javassist就提供了一些方便的方法,让我们通过这些方法生成字节码。

要想将编译时不存在的类在运行时动态创建并加载,通常有两种策略:

1.      动态编译

2.      动态生成二进制字节码(.class)

对于第二种策略,实际上已经有诸多比较成熟的开源项目提供支持,如CGLib、ASM、Javassist等。这些开源项目通常都具备两方面的功能:

1.      动态创建新类或新接口的二进制字节码

2.      动态扩展现有类或接口的二进制字节码

其中,CGLib的底层基于ASM实现,是一个高效高性能的生成库;而ASM是一个轻量级的类库,但需要涉及到JVM的操作和指令;相比而言,Javassist要简单的多,完全是基于Java的API,但其性能相比前二者要差一些。

尽管如此,在性能要求相对低的场合,Javassist仍然十分有用,如JBoss中就调用了Javassist。

如下的代码是动态创建Java类二进制字节码并通过反射调用的示例,可供参考:

package com.test.TestForDubbo;

import java.lang.reflect.Method;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtNewMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.CtField.Initializer;  

public class javassistGenerator {

	public static void main(String[] args) throws Exception{
		// 创建类
		ClassPool pool = ClassPool.getDefault();
		CtClass cls = pool.makeClass("com.cn.alal.TestClass");

		 // 添加私有成员name及其getter、setter方法
        CtField param = new CtField(pool.get("java.lang.String"), "name", cls);  

        param.setModifiers(Modifier.PRIVATE);
        cls.addMethod(CtNewMethod.setter("setName", param));
        cls.addMethod(CtNewMethod.getter("getName", param));
        cls.addField(param, Initializer.constant(""));  

        // 添加有参的构造体
        CtConstructor  cons = new CtConstructor(new CtClass[] {pool.get("java.lang.String")}, cls);
        cons.setBody("{$0.name = $1;}");
        cls.addConstructor(cons);  

        // 打印创建类的类名
        System.out.println(cls.toClass());

        // 通过反射创建无参的实例,并调用getName方法
        Object o = Class.forName("com.cn.alal.TestClass").newInstance();
        Method getter = o.getClass().getMethod("getName");
        System.out.println(getter.invoke(o));  

        // 调用其setName方法
        Method setter = o.getClass().getMethod("setName", new Class[] {String.class});
        setter.invoke(o, "Adam");
        System.out.println(getter.invoke(o));  

        // 通过反射创建有参的实例,并调用getName方法
        o = Class.forName("com.cn.alal.TestClass").getConstructor(String.class).newInstance("Liu Jian");
        getter = o.getClass().getMethod("getName");
        System.out.println(getter.invoke(o));  

	}

}
时间: 2024-08-02 21:18:23

Dubbo源码分析(八):Javassist字节码技术生成代理的相关文章

dubbo源码分析三:consumer注册及生成代理对象

本章我们将分析一下consumer向注册中心注册,并获取服务端相应的信息,根据这些信息生产代理对象的过程和源码. 1.类图 上图展示了部分消费者注册及生成代理对象过程中需要使用到的类和接口,其中: spring适配涉及到的类:DubboNamespaceHandler.DubboBeanDefinitionParser.ReferenceBean; 配置信息存储:ReferenceConfig.RegistryConfig.MonitorConfig.ProtocolConfig.Consume

cglib源码分析(三):Class生成策略

cglib中生成类的工作是由AbstractClassGenerator的create方法使用相应的生成策略完成,具体代码如下: private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE; byte[] b = strategy.generate(this); GeneratorStrategy是一个接口,它负责调用ClassGenerator 的generateClass方法来生成类.DefaultGenera

Pig源码分析: 简析执行计划的生成

摘要 本文通过跟代码的方式,分析从输入一批Pig-latin到输出物理执行计划(与launcher引擎有关,一般是MR执行计划,也可以是Spark RDD的执行算子)的整体流程. 不会具体涉及AST如何解析.如何使用了Anltr.逻辑执行计划如何映射.逻辑执行计划如何优化.MR执行计划如何切分为MR Job,而是从输入一批Pig DSL到待执行的真正执行计划的关键变化步骤(方法和类). 执行计划完整解析 入口处书Main类的main函数 /** * The Main-Class for the

【JDK源码分析】通过源码分析CyclicBarrier

前言 CyclicBarrier它是什么?一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点.类似于朋友之间联系要在中午聚个会,几个朋友全部到齐后才开始喝酒吃菜. 源码 CyclicBarrier属性和构造器 public class CyclicBarrier { // 互斥锁 private final ReentrantLock lock = new ReentrantLock(); // 条件等待 private final Condition trip = lock.new

5.Dubbo原理解析-代理之Javassist字节码技术生成代理 (转)

转载自  斩秋的专栏  http://blog.csdn.net/quhongwei_zhanqiu/article/details/41597219 JavassistProxyFactory:利用字节码技术来创建对象 public <T> T getProxy(Invoker<T> invoker,Class<?>[] interfaces) { return (T) Proxy.getProxy(interfaces).newInstance(new Invoke

JAVAssist字节码操作

Java动态性的两种常见实现方式 字节码操作 反射 运行时操作字节码可以让我们实现如下功能: 动态生成新的类 动态改变某个类的结构(添加/删除/修改  新的属性/方法) 优势: 比反射开销小,性能高 JAVAasist性能高于反射,低于ASM 常见的字节码操作类库 BCEL 这是Apache Software Fundation的jakarta项目的一部分.BCEL是javaclassworking广泛使用的一种跨级啊,它可以让你深入JVM汇编语言进行类的操作的细节.BCEL与javassist

Javassist字节码增强示例

概述 Javassist是一款字节码编辑工具,可以直接编辑和生成Java生成的字节码,以达到对.class文件进行动态修改的效果.熟练使用这套工具,可以让Java编程更接近与动态语言编程. 下面一个方法的目的是获取一个类加载器(ClassLoader),以加载指定的.jar或.class文件,在之后的代码中会使用到. [java] view plaincopy private static ClassLoader getLocaleClassLoader() throws Exception {

搭建agent服务+javassist字节码操作

简介 对于agent,是在vm启动,执行方法前,将字节码修改的服务代理. 对于javassist,是修改字节码具体实现. 这两个结合有什么用啊?写测试框架,不仅局限于此. 对于字节码: 字节码处理工具,bcel,asm与虚拟机指令打交道.Javassist采用java编码的方法处理字节码,性能相对较低,但方便. 官方:http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ 例子: 创建class http://blog.csdn.net/sadfi

[python] 词云:wordcloud包的安装、使用、原理(源码分析)、中文词云生成、代码重写

词云,又称文字云.标签云,是对文本数据中出现频率较高的“关键词”在视觉上的突出呈现,形成关键词的渲染形成类似云一样的彩色图片,从而一眼就可以领略文本数据的主要表达意思.常见于博客.微博.文章分析等. 除了网上现成的Wordle.Tagxedo.Tagul.Tagcrowd等词云制作工具,在python中也可以用wordcloud包比较轻松地实现(官网.github项目): from wordcloud import WordCloud import matplotlib.pyplot as pl