反射的应用---动态代理

本文介绍了静态代理和动态代理的概念及其在Java中的实现。静态代理通过预先定义的代理类实现对目标类的增强,但存在代码冗余的问题。动态代理则在运行时动态生成代理类,解决了静态代理的局限性,更加灵活。文中通过代码示例展示了如何使用Java的Proxy和InvocationHandler接口来创建和操作动态代理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

先通过一段代码回顾一下静态代理:

/**
 * 静态代理举例
 */

//接口
interface ClothFactory{
    void produceCloth();  //生产服装
}

//代理类
class ProxyClothFactory implements ClothFactory{
    private ClothFactory factory;   //用被代理类对象进行实例化

    public ProxyClothFactory(ClothFactory factory) {
        this.factory=factory;
    }
    
    @Override
    public void produceCloth() {
        System.out.println("代理工厂做一些准备工作");
        factory.produceCloth();
        System.out.println("代理工厂做一些后续收尾工作");
    }
}

//被代理类
class NikeClothFactory implements ClothFactory{
    @Override
    public void produceCloth() {
        System.out.println("耐克工厂生产一批运动服装");
    }
}

//测试
public class StaticProxyTest {
    public static void main(String[] args) {
        NikeClothFactory nike = new NikeClothFactory();
        ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);
        proxyClothFactory.produceCloth();
    }
}

运行:
在这里插入图片描述

静态代理之所以为静态,是因为在编译期间代理类和被代理类都已经确定了下来。


静态代理中一个被代理类对应一个代理类,存在代码量大且不宜维护等缺点,因此引入动态代理。


在这里插入图片描述

动态代理举例:

package com.atguigu.java;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 动态代理的举例
 */
interface Human{
    String getBelief();
    void eat(String food);
}

//被代理类
class SuperMan implements Human{
    @Override
    public String getBelief() {
        return "I believe I can fly.";
    }
    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃"+food);
    }
}

/*  要想实现动态代理,需要解决两个问题:
            问题一:如何根据加载到内存中的被代理类,动态创建一个代理类及其对象
            问题二:当通过代理类的对象调用方法a时,如何动态地去调用被代理类中的同名方法a
*/
//写一个生产代理类的工厂
class ProxyFactory{
    //调用此方法返回一个代理类的对象,解决问题一
    public static Object getProxyInstance(Object obj){    //传入的obj是被代理类的对象,根据此对象 动态地 造一个代理类对象,此方法返回值类型Object可转为某一个具体代理类的类型
        MyInvocationHandler handler = new MyInvocationHandler(); //作为参数3
        handler.bind(obj);  //此处相当于赋值
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
        //参数1:表示被代理类对象obj是哪个类的加载器加载的,代理类对象也用此加载器加载
        //参数2:表示被代理类对象obj实现了哪些接口,代理类对象也实现这些接口
        //参数3:是InvocationHandler(是接口)类型,传入此参数解决问题二
    }
}

//InvocationHandler是一个接口,需要我们自定义一个此接口实现类
class MyInvocationHandler implements InvocationHandler{

    private Object obj;    //声明为Object,但需要使用被代理类对象赋值
    public void bind(Object obj){   //绑定方法赋值(相当于一个set方法)
        this.obj=obj;
    }
    //当通过代理类对象调用方法时,就会自动地调用如下的invoke方法。所以将 被代理类 要执行的功能(方法)声明在invoke方法中。
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //参数1 proxy其实是就是上面返回的代理类对象;
        //参数2 method是代理类调用的那个方法,此方法也就作为被代理类对象要调用的方法
        //参数3 args是同名的方法的参数
        Object returnValue=method.invoke(obj,args);    //obj是 被代理类的对象
        //上述方法的返回值就作为当前类中invoke()方法的返回值
        return returnValue;
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        //先造一个被代理类的对象
        SuperMan superMan = new SuperMan();
        //看superMan实现了什么接口,造一个实现这些接口的代理类,所以不能用superMan类型接收,可以使用 他们共同的Human接口类型接收
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);  //获取代理类对象
        String belief = proxyInstance.getBelief();
        System.out.println(belief);      //I believe I can fly.
        proxyInstance.eat("四川麻辣烫"); //我喜欢吃四川麻辣烫

        System.out.println("****************");
        //动态代理:不通过自定义代理类,通过被代理类和接口动态创建一个代理类
        NikeClothFactory nikeClothFactory = new NikeClothFactory(); // 创建一个被代理类
        ClothFactory proxyClothFactory= (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory); //强转为接口类型
        proxyClothFactory.produceCloth();     //耐克工厂生产一批运动服装
    }
}

在这里插入图片描述

静态代理的代理类是直接写好的;动态代理没有在编译时显式定义代理类,而是在运行时根据传进来的被代理类对象是谁,动态方式创建代理类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过期动态

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值