当前位置:主页 > 查看内容

java动态代理 - 夜雨夕眠

发布时间:2021-05-03 00:00| 位朋友查看

简介:java动态代理 1. 简介 java的动态代理功能是用来解决现有类功能不足,但我们又不想去修改现有类方法的问题,或者就是我们无法直接使用现有类的情况。它的实现方式有两种,第一种是jdk自带的动态代理功能,它的实现前提是现有类必须拥有一个接口,因为它是通过对……

java动态代理

1. 简介

java的动态代理功能是用来解决现有类功能不足,但我们又不想去修改现有类方法的问题,或者就是我们无法直接使用现有类的情况。它的实现方式有两种,第一种是jdk自带的动态代理功能,它的实现前提是现有类必须拥有一个接口,因为它是通过对现有类接口的实现来完成的。第二种方式是cglib,这是一个开源工具包,它的实现是通过继承现有类,然后重写现有类的方法实现的。它们在spring与mybatis框架中均有使用。学习它们的前提是你要对java的反射机制有一定的认知。本篇只介绍jdk原生的动态代理。

2. jdk动态代理

2.1 演示前景

客户:购买u盘

代理商:淘宝

u盘工厂:金士顿,三星等

用户想要购买u盘,是不可以直接去厂家购买的,需要通过淘宝等代理商进行购买,抽象成程序就是,u盘工程就是目标类,也就是现有类,淘宝就是代理类,客户就是用户类.用户需要调用淘宝的方法进行购买u盘,而淘宝又需要调用工厂的方法进行购买.如果我们直接创建一个淘宝类,让它去代理金士顿工厂,就会出现一个问题,那就是三星工厂由谁去代理,总不能再创建一个代理类吧,所以就可以使用动态代理的方式,在程序运行时期,根据不同的情况去创建一个合适的代理类

2.2编写代码

首先我们需要一个工厂的接口UsbFactory

package com.hzq.application.targetclass;

public interface UsbFactory {
    //售卖u盘,并返回实际价格的方法
    float sell(int num);
}

第二步就是创建一个UsbFactory的实现类UsbKingFactory代表金士顿工厂

package com.hzq.application.targetclass.impl;

import com.hzq.application.targetclass.UsbFactory;

public class UsbKingFactory implements UsbFactory {
    @Override
    public float sell(int num) {
        float onePrice = 30.0F;
        float price = onePrice * num;
        System.out.println("向厂家购买花费了"+price+"元");
        return price;
    }
}

现在需要我们代理的目标类已经好了,接下来就是重点了,jdk动态代理的实现方法(这个实现套路是固定的)。第三步,创建一个MyInvocationHandler类去实现接口InvocationHandler。这个接口只有一个需要我们去实现的方法,那就是invoke()方法,它有3个参数,第一个参数其实就是我们后面通过动态代理去创建的代理类,这个参数不需要我们的参与,不用去理会,第二个参数是我们要去增强的目标类的方法,第三个是该方法的参数.invoke内部就是我们要对目标类的方法增强的具体逻辑,也就是我们想怎样去增强它,在本示例中我们是对用户购买的商品收取20元中介费,然后送给用户一张10元的优惠券

package com.hzq.application.proxy;

import com.hzq.application.targetclass.UsbFactory;

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

public class MyInvocationHandler implements InvocationHandler {
    private UsbFactory factory ;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      //1.调用目标类的售卖方法,然后返回价格
        Float price = (Float) method.invoke(factory, args);
      //2.我们在之后进行自定义的增强,这里我们是抽取20元的中介费用,然后送给客户一张10元优惠券
        price += 20;
        System.out.println("代理商送您一张10元优惠券");
        System.out.println("客户购买商品花费了"+price+"元");
        return price;
    }

    public MyInvocationHandler(UsbFactory factory) {
        this.factory = factory;
    }
}

最后一步就是去使用jdk动态代理来在运行期创建一个代理类对象了,在代码中第第三步是重点,我们如果我们想要创建一个动态代理类,就必须要调用Proxy类的静态方法newProxyInStance()方法,这个方法会返回给我们一个代理类对象,我们实际购买商品也是通过这个代理类来进行购买的。newProxyInstance()方法一共有三个参数,第一个参数是一个类加载器对象,类加载器对象可以通过目标类的Class对象去调用getClassLoader()方法去获取,其实也可以使用其他你自定义的类的Class对象去获取,因为最后获得的都是同一个类加载器实例,但为了代码的易读性,就使用了目标类。第二个参数是目标类的接口类型,第三个参数就是我们自定义的MyInvocationHandler类的实例对象了,它里面封装这我们具体的增强逻辑代码。方法调用完成后,如果没有出现问题就会返回给我们一个代理类的实例,之后我们就可以去使用这个代理类的。

package com.hzq.application;

import com.hzq.application.proxy.MyInvocationHandler;
import com.hzq.application.targetclass.UsbFactory;
import com.hzq.application.targetclass.impl.UsbKingFactory;

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

public class ProxyMain {
    public static void main(String[] args) {
      //1.实例化一个金士顿工厂对象
        UsbFactory usbFactory = new UsbKingFactory();
      //2.实例化一个MyInvocationHandler对象
        InvocationHandler handler = new MyInvocationHandler(usbFactory);
      //3.通过jdk动态代理创建出代理对象
        UsbFactory proxyInstance = (UsbFactory) Proxy.newProxyInstance(usbFactory.getClass().getClassLoader(),
                usbFactory.getClass().getInterfaces(),
                handler);
      //4.通过代理对象来购买商品
        float price = proxyInstance.sell(3);
        System.out.println(price);
    }
}

最后,当我们需要代理其他工厂去售卖u盘时,只需要将main方法中的第一步实例化的金士顿工厂改成其他品牌的工厂即可,当然前提是这个工厂的类实现了UsbFactory接口。

2.3 总结

当我们去使用jdk动态代理时,首先需要确保目标类实现了接口。之后的使用步骤就是:

  1. 实现InvocationHandler接口,将我们具体的增强逻辑代码写在invoke()方法中
  2. 使用Proxy类的newProxyInstance()方法去创建一个代理类的实例对象.
  3. 使用这个代理类对象
-原文链接:https://www.cnblogs.com/night-rainy/p/14616580.html
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:Linux安装docker-ce教程 centos依赖包安装 下一篇:没有了

推荐图文


随机推荐