JDK动态代理

 Java允许我们在运行时创建某个接口或类的动态代理。什么是动态代理?首先了解一下静态代理(代理设计模式):代理设计模式能够让我们无需修改源代码,进而对源接口功能进行增强(开闭原则,对修改封闭,对扩展开放)。

package com.lz.proxy;

interface Behaviour {
    int action();
}

// 被代理类,实现了Behaviour接口
class Target implements Behaviour {
    @Override
    public int action() {
        System.out.println("action...");
        return 1;
    }
}

// 代理类,也实现了Behaviour接口
class TargetProxy implements Behaviour {
    private Behaviour target; // 内部持有被代理类的对象

    TargetProxy(Behaviour target) {
        this.target = target;
    }

    @Override
    public int action() { // 增强的action方法,在被代理对象的action行为基础上进行扩展
        before();
        int result = target.action();
        after();
        return result;
    }

    private void before() {
        System.out.println("before action...");
    }

    private void after() {
        System.out.println("after action...");
    }
}

public class StaticProxyDemo {
    private static void consume(Behaviour item) { // 消费实现了Behaviour接口的类的对象
        int result = item.action();
        System.out.println("get result: " + result);
    }

    public static void main(String[] args) {
        Behaviour target = new Target();
        consume(target);

        System.out.println("\n*** proxy ***");
        Behaviour proxy = new TargetProxy(target);
        consume(proxy);
    }
}

 Target类实现了Behaviour接口,能够供consume方法“消费”。而TargetProxy类也实现了Behaviour接口,并内部持有一个Behaviour“类型”的引用,由此能够对接口功能进行扩展。


 静态代理是在编译之前,我们编写好的Java代码(.java文件),编译器把它编译成字节码文件(.class文件),进而加载到JVM中,以便使用。而动态代理的思想是:编译期间并不知道代理类的存在,而是在运行时生成代理类字节码加载到虚拟机并创建代理对象,通过反射技术,动态地处理对所代理方法的调用。JDK对此提供了Proxy类。

package com.lz.proxy;

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

class DynamicProxyHandler implements InvocationHandler {
    private Object target;

    DynamicProxyHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("action")) {
            System.out.println("*** dynamic proxy ***");
            System.out.println("method: " + method.getName());
            Object result = method.invoke(target, args); // 对原方法的调用
            System.out.println("*** dynamic proxy ***");
            return result;
        } else {
            return method.invoke(target, args);
        }
    }
}

public class DynamicProxyDemo {
    private static void consume(Behaviour item) {
        int result = item.action();
        System.out.println("get result: " + result);
    }

    public static void main(String[] args) {
        Behaviour target = new Target();
        // 通过Proxy的newProxyInstance方法在运行时创建代理对象
        Behaviour proxy = (Behaviour) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                new Class[]{Behaviour.class}, new DynamicProxyHandler(target));
        consume(proxy);

        /* output:
         * *** dynamic proxy ***
         * method: action
         * action...
         * *** dynamic proxy ***
         * get result: 1
         */
    }
}

 注意到DynamicProxyHandler类实现了InvocationHandler接口,此接口只有一个invoke方法。该类中每还持有一个被代理对象的引用。每一个代理对象都会关联一个实现了InvocationHandler接口的对象,通过invoke方法用来对方法进行增强。当通过代理对象调用方法时,都会被“转发”到invoke方法。invoke参数中,proxy就是代理对象,method是被代理的方法,args是传入方法的参数。可以通过method、args等信息各个方法作出相应的“动作”。


 Proxy.newInstance()方法接受三个参数:生成代理类的类加载器、代理类要实现(代理)的接口列表和调用处理器。JDK动态代理的弊端就是只能对接口进行代理,原因是生成的代理类继承了Proxy类,而Java有只允许单继承,所以代理对象只能通过实现接口进行代理了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值