Java学习笔记

动态代理

学习黑马程序员的知识总结,文章代码并非原创,文字为自己总结所得

基于JDK的动态代理

使用:

proxy = Proxy.newProxyInstance(ClassLoader loader,
                                Class<?>[] interfaces,
                                InvocationHandler h)

第一个参数:类加载器,通常传入目标对象的类加载器即可:
eg: target.getClass().getClassLoader() 一般都是固定的这么写的,也可以传入null 使用默认加载器
第二个参数:***实现了接口***的字节码对象,通常传入
eg: target.getClass().getInterfaces() 一般也是固定这么写
第三个参数是重点关注对象,它传入了InvocationHandler对象

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

该对象只实现了应该invoke方法,proxy即为代理类对象,在动态代理中无需关注,会自己生成;
method参数,就是方法的反射,在原对象中执行上面方法,都会调用到invoke()方法中,调用形式为 method.invoke(object , args) object 为实际执行method的对象,args为存储实际方法参数的数组

使用示例:
代码1:OrderInterface接口

package jdk_proxy;

public interface OrderInterface {
    public String order(String foodName);
    public void test();
    public void test2();
}

代码2:定义应该实现了 OrderInterface 接口的customer类

package jdk_proxy;
public class Customer implements OrderInterface{
    @Override
    public String order(String foodName) {
        return "已经下单"+ foodName;
    }

    @Override
    public void test() {

    }

    @Override
    public void test2() {

    }
}

代码3:动态代理的测试类

package jdk_proxy;

import java.lang.reflect.Proxy;

public class DynamicTest {
    public static void main(String[] args) {
        Customer customer = new Customer();
        OrderInterface deliveryClerk = (OrderInterface) Proxy.newProxyInstance(
                customer.getClass().getClassLoader(),
                customer.getClass().getInterfaces(),
                ((proxy, method, args1) -> {
                    Object result = method.invoke(customer, args1);
                    System.out.println("接收到订单");
                    System.out.println("正在派送");
                    return result + "结束";
                }));
        String result = deliveryClerk.order("麻婆豆腐");
        System.out.println(result);
    }
}

基于上述使用示例剖析底层原理
上述示例的代理对象是在运行时自动生成的,接下来我们自己写一个代理对象,模仿JDK运行时,生成的代理对象的工作过程

package jdk_proxy.explain;

import jdk_proxy.OrderInterface;

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

public class DeliveryClerk implements OrderInterface {

    private InvocationHandler handler;
    public DeliveryClerk(InvocationHandler handler){
        this.handler = handler;
    }

    @Override
    public String order(String foodName) throws Throwable {
        Method method = OrderInterface.class.getMethod("order", String.class);
        Object result =  handler.invoke(this, method, new Object[] {foodName});
        return (String) result;
    }

    @Override
    public void test() {
        try {
            Method method = OrderInterface.class.getMethod("test");
            Object result =  handler.invoke(this, method, null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }

    @Override
    public void test2() {
        try {
            Method method = OrderInterface.class.getMethod("test2");
            Object result =  handler.invoke(this, method, null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

可以看到改代理类和目标类(customer)是实现了相同的接口,并且构造函数传入了一个InvocationHandler对象,和上述动态代理中的第三个参数是一样的。
这个代理类实现了接口的所有方法,并且在实现每一个方法时都调用了InvocationHandler 对象的invoke()方法,这也就是为什么,只要代理对象调用方法时就一定会走到invoke()方法的原因。同上invoke()方法有3个参数,Object proxy, Method method, Object[] args
proxy即为代理对象,也就是我们写的代理对象自己,所以传入this即可;
method为方法对象,这里要使用反射机制,获取当前执行的方法代理方法;
args依然为当前方法的参数,所以order()方法中传入了foodName, 而两个test()方法,因为都没有参数所以传入null。
下面我们到动态代理测试代码中使用这个代理类,如果实现结果与上述代码相同,则说明我们自己写的这个代理类是能正确模拟JDK动态生成的代理类的。

package jdk_proxy;

import jdk_proxy.explain.DeliveryClerk;

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

public class DynamicTest {
    public static void main(String[] args) throws Throwable {
        Customer customer = new Customer();
//        OrderInterface deliveryClerk = (OrderInterface) Proxy.newProxyInstance(
//                customer.getClass().getClassLoader(),
//                customer.getClass().getInterfaces(),
//                ((proxy, method, args1) -> {
//                    Object result = method.invoke(customer, args1);
//                    System.out.println("接收到订单");
//                    System.out.println("正在派送");
//                    return result + "结束";
//                }));

        InvocationHandler handler = ((proxy, method, args1) -> {
                    Object result = method.invoke(customer, args1);
                    System.out.println("接收到订单");
                    System.out.println("正在派送");
                    return result + "结束";
                });
        OrderInterface deliveryClerk = new DeliveryClerk(handler);
        String result = deliveryClerk.order("麻婆豆腐");
        System.out.println(result);
    }
}

最终我们可以看到他们的运行结果是一致的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值