JAVA反射(三)

这篇博客主要探讨JAVA的动态代理机制,以解决静态代理中的不便。通过动态代理,我们可以根据消费者的不同需求动态创建代理对象,避免重复编写多个代理类。文章详细讲解了如何创建动态代理类,实现InvocationHandler接口,以及如何使用Proxy的newProxyInstance()方法生成代理对象。最后,展示了动态代理的invoke()方法执行过程,揭示了其在AOP(面向切面编程)中的应用。

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

关于JAVA的反射机制,动态代理是一大重要的功能,今天主要就来说一说动态代理。提到代理,想必大家都不陌生,简单的理解就是代理充当着代替办某件事的一个角色,既然有动态代理,那就有静态代理,先看看一个比较简单的静态代理:
假设我们有一个名为Consumer消费者的接口,其中包含购买饮料食物buyDrink和购买食物buyFood的方法:

public interface Consumer {
    public void buyFood();

    public void buyDrink();
}

这时有一个消费者A需要购买进口食品和饮料:

public class ConsumerA implements Consumer {
    @Override
    public void buyFood() {
        System.out.println("买进口牛肉");
    }

    @Override
    public void buyDrink() {
        System.out.println("买进口果汁");
    }
}

购买进口食品需要通过代购,假设有一个消费者A的代理类:

public class ConsumerAProxy implements Consumer {
    private ConsumerA consumer;

    public ConsumerAProxy(){
        consumer=new ConsumerA();
    }

    @Override
    public void buyFood() {
        System.out.println("-----开始代理-----");
        consumer.buyFood();
        System.out.println("-----结束代理-----");
    }

    @Override
    public void buyDrink() {
        System.out.println("-----开始代理-----");
        consumer.buyDrink();
        System.out.println("-----结束代理-----");
    }
}

接下来写一个测试类,运行即可:

 public static void main(String[] args) {
        ConsumerAProxy cap=new ConsumerAProxy();
        cap.buyFood();
        cap.buyDrink();

    }

运行结果:
在这里插入图片描述
这是一个简单的静态代理,在此过程中就会出现一个问题:
假设现有一个消费者B,需要购买其他进口产品,比如进口牛奶等等,那么如果按照这种模式,我们需要再次创建一个新的消费者B类实现消费者接口,并且重写方法,由于购买的东西不同,代理对象(即代购类)也需要重新编写一个,那么如果有多个消费者,需求也不同,就得编写多套不同的类,这样很明显是麻烦的。那如果我们能将代理对象写成一个动态的,即能根据消费者的需求完成相应的代购,就可以解决这个问题了,这就是动态代理,通过反射可以实现。

首先编写一个动态代理类:

public class DynamicProxy implements InvocationHandler

要想实现动态代理,该类必须继承InvocationHandler接口,而该接口中只有一个方法invoke,后面我们慢慢解释该方法。
既然是代理,那么我们需要有一个代理的目标对象,即我们想要对哪一名消费者进行代理,由于该代理是动态的,不确定,我们用Object类表示:

	//目标对象
    private Object target;

接下来是生成相应的代理对象,编写一个返回值为object类,参数为目标对象的方法(目标对象可变,生成的代理对象也不确定,就用Object类表示):

 public Object newProxyInstance(Object target)

将传入的目标对象target赋给本类的目标对象target,这样就能确定为谁代理:

this.target=target;

下一步返回代理类Proxy中newProxyInstance()方法产生的实例:

 return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);

我们可以先看看该方法:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

该方法包含三个参数:

其中第一个参数代表目标对象的类加载器,即我们想指定生成哪个类的实例

而第二个参数代表目标对象实现的接口,这里我们可以看之前的静态代理:
在这里插入图片描述
比如消费者A的代理实现了消费者接口,这一步实际上是确定了该对象会包含哪些方法

第三个参数代表实现了InvocationHandler接口的实例(通常就是当前类),目的是为了执行接口中的invoke()方法。

这样一个生成代理对象的方法就完成了,接下来我们看重写的invoke方法:

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

同样该方法需要三个参数:
第一个参数代表我们传入的代理对象,第二个参数代表我们要代理执行的方法,第三个则是执行方法需要的参数。

接下来对方法进行执行:

method.invoke(target,args);

invoke()方法在反射时已经说过,第一个参数代表指定调用哪个实例的方法,第二个参数代表执行该方法时的参数,该方法返回值为Object:

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----代理开始------");

        Object object= method.invoke(target,args);

        System.out.println("-----代理结束------");
        return object;
    }

这样就完成了一个简单的动态代理,在执行时我们只需这样写即可:

		DynamicProxy dp=new DynamicProxy();
        Consumer consumer= (Consumer) dp.newProxyInstance(new ConsumerA());
        consumer.buyDrink();
        consumer.buyFood();

需要对哪个对象进行代理,我们直接创建代理对象实例的方法中传入想要代理的对象即可,而在上述
invoke方法中我们也能发现:
在这里插入图片描述
实际上这三步除了中间的invoke方法中的参数不确定外,上下两行打印语句都是一成不变的,这也是AOP的一次体现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值