添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

代理分两种技术,一种是jdk代理(机制就是反射,只对接口操作),一种就是字节码操作技术。前者不能算技术,后者算是新的技术。未来将有大的动作或者较为广泛的应用和变革,它可以实现代码自我的编码(人工智能,代码智能)。

先看看jvm class技术:

字节码改写:

(一)jdk 动态代理:

1.定义业务逻辑

public interface Service {  
    //目标方法 
    public abstract void add();  
public class UserServiceImpl implements Service {  
    public void add() {  
        System.out.println("This is add service");  
java.lang.reflect.Proxy 
java.lang.reflect.InvocationHandler 
接口定义代理类的实现。 
class MyInvocatioHandler implements InvocationHandler {
    private Object target;
    public MyInvocatioHandler(Object target) {
        this.target = target;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----before-----");
        Object result = method.invoke(target, args);
        System.out.println("-----end-----");
        return result;
    // 生成代理对象
    public Object getProxy() {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        return Proxy.newProxyInstance(loader, interfaces, this);

3.使用动态代理
public class ProxyTest {
    public static void main(String[] args) {
        Service service = new UserServiceImpl();
        MyInvocatioHandler handler = new MyInvocatioHandler(service);
        Service serviceProxy = (Service)handler.getProxy();
        serviceProxy.add();

执行结果:

-----before-----
This is add service
-----end-----

代理对象的生成过程由Proxy类的newProxyInstance方法实现,分为3个步骤:
1、ProxyGenerator.generateProxyClass方法负责生成代理类的字节码,生成逻辑比较复杂,了解原理继续分析源码 sun.misc.ProxyGenerator;

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

2、native方法Proxy.defineClass0负责字节码加载的实现,并返回对应的Class对象。

Class clazz = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);

3、利用clazz.newInstance反射机制生成代理类的对象;

使用 反编译工具 jad jad com.sun.proxy.$Proxy.1 看看代理类如何实现,反编译出来的java代码如下:

public final class $proxy1 extends Proxy implements Service {
    public $proxy1(InvocationHandler invocationhandler) {
        super(invocationhandler);
    public final boolean equals(Object obj) {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[] {
            })).booleanValue();
        catch(Error _ex) { }
        catch(Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
    public final String toString() {
        try {
            return (String)super.h.invoke(this, m2, null);
        catch(Error _ex) { }
        catch(Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
    public final void add() {
        try {
            super.h.invoke(this, m3, null);
            return;
        catch(Error _ex) { }
        catch(Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
    public final int hashCode() {
        try {
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        catch(Error _ex) { }
        catch(Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    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("zzzzzz.Service").getMethod("add", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        catch(NoSuchMethodException nosuchmethodexception) {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        catch(ClassNotFoundException classnotfoundexception) {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
从上述代码可以发现: 
1、生成的$proxy1继承自Proxy类,并实现了Service接口。 
2、执行代理对象的方法,其实就是执行InvocationHandle对象的invoke方法,传入的参数分别是当前代理对象,当前执行的方法和参数。 

jdk动态代理使用的局限性
通过反射类ProxyInvocationHandler回调接口实现的jdk动态代理,要求委托类必须实现一个接口,但事实上并不是所有类都有接口,对于没有实现接口的类,便无法使用该方方式实现动态代理。

(二)字节码修改技术

了解该技术必然先了解Java class文件格式 读《深入jvm原理》之class文件

目前字节码修改技术有ASM,javassist等。cglib就是基于封装的Asm. Spring 就是使用cglib代理库。

ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
不过ASM在创建class字节码的过程中,操纵的级别是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有一定的了解。

Java字节码生成开源框架介绍--Javassist:

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。

注解、反射、字节码操作 前言:本篇博客将介绍Java中注解的定义、使用以及反射对Java动态性的支持和Java字节码操作,通过本篇内容,读者将对Java知识有更加深刻的理解,同时为后面Android的高级框架学习打好基础。 Annotation是从JDK5.0开始引入的,注解并不是程序本身,但可以被其他程序读取,如果没有注解信息处理流程,注解将毫无意义。注解可以在Java很多地方使用,如类、属性、方法等等。 1-注解入门 2-内置注解 3-自定义注解、元注解
反射机制概述 reflection:java是一门静态语言,但是因为有反射机制,成为了准动态语言,反射机制允许程序在运行期间借助与Reflection API取得任何类的内部信息,并且能够直接操作任意对象内部属性及其方法。 在加载完类之后,在堆内的方法区就会产生一个class类型的对象,这个对象就包含了完整的类结构信息,我们可以通过这个对象看到类的结构。这个对象就是一面镜子,通过这个镜子看到类的结构,所以形象的称为反射。 代码解释: public class ReflectionTest {
获取字节码的三种方法: 1)Class clazz1 = Class.forName("全限定类名"); //通过静态方法forName,获取字节码文件对象。此时该类还处于源文件java文件阶段,并没有变为字节码.class文件。 2)Class clazz2 = Person.class; //在类被编译成.class文件时启动,直接获取到自己编译成的.class文件。 3)Class c...
普通的new一个对象: // 先拿到Class对象 Class<?> aClass = Class.forName("org.chabug.entity.ReflectionClass"); // new这个Class对应的对象 Object o = aClass.newInstance(); 普通的public方法可以直接调用:这里是调用set
两个写的不错的博客,转过来学习 java字节码文件详解https://blog.csdn.net/mydreamremindme/article/details/9261451 java反射 https://blog.csdn.net/sinat_38259539/article/details/71799078 Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.2:sonar (default-cli) on p CSDN-Ada助手: MyBatis里的参数 # 和 $ 引用的差异是什么? 关于 android listview 加载数据错位(错乱)问题 假装认真的青铜: 写法就是这样,但是还是错乱了,比如说增加列表或者删除列表中的item行