当前位置 > it书童 > java > 正文

Java 动态代理实现方法增强详解

java it书童 2020-08-14 10:03:11 0赞 0踩 85阅读 0评论

实现接口常规方式

了解动态代理之前,先演示下常规的实现接口流程

  1. 定义接口

Animal 接口

public interface Animal {
    void run();
}
  1. 实现接口

Cat 类

public class Cat implements Animal {
    @Override
    public void run() {
        System.out.println("小猫跑酷");
    }
}
  1. 调用
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.run();
    }
}

结果:

小猫跑酷

动态代理

如果我们不想编写实现类,在运行期创建接口的实例,就可以用到 Java 标准库提供的动态代理 (Dynmaic Proxy) 机制。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if (method.getName().equals("run")) {
                    System.out.println("小猫在客厅和主卧之间跑酷");
                }
                return null;
            }
        };

        Animal animal = (Animal) Proxy.newProxyInstance(
            Animal.class.getClassLoader(), // 传入 ClassLoader
            new Class[] { Animal.class }, // 传入要实现的接口
            handler // 传入处理调用方法的 InvocationHandler
        );
        animal.run();
    }
}

结果:

小猫在客厅和主卧之间跑酷

代码分析:

  1. InvocationHandler 负责实现接口的方法调用

  2. Proxy.newProxyInstance 创建 interface 实例

  3. 将返回的 Object 强制转型为接口

动态代理的实质:JDK 在运行期动态创建 class 字节码并加载的过程。并不存在可以直接实例化接口的黑魔法

动态代理实现方法增强

需求:我们不想改变类的源码,同时在其方法上增加新的功能

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        // 原对象,向上转型
        final Animal cat = new Cat();
        // 动态代理
        Animal catProxy = (Animal) Proxy.newProxyInstance(
            cat.getClass().getClassLoader(),
            cat.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 增强 run 方法
                    if (method.getName().equals("run")) {
                        method.invoke(cat, args); // 调用原对象的方法,保留原方法的功能
                        // 新增功能
                        System.out.println("从客厅跑到主卧");
                    }
                    return null;
                }
            }
        );
        catProxy.run();
    }
}

结果:

小猫跑酷
从客厅跑到主卧
转载须注明出处:https://www.itshutong.com/articles/614/java-dynamic-proxy-implementation-method-enhancement-details
关于我
一个文科出身的程序员,追求做个有趣的人,传播有价值的知识,微信公众号主要分享读书思考心得,不会有代码类文章,非程序员的同学请放心订阅
发表评论
我有句话,不知当讲不当讲?
要讲之前请先 登录