Java动态代理

代理模式

代理模式就是代理对象完成用户的请求,屏蔽用户对真是对象的访问。
打个比方,在早些年间我们要买电脑,都是直接跟电脑生产厂家进行交易,我们付款给生产厂家,然后厂家发货给我们。随着生产厂家的业务发展,用户越来越多,对商品的销售和售后需要付出更多的财力和物力。这时,一些人洞察了这一机遇,就搞了了一个叫代理商/经销商的东西出来,如某宝,某东。后来,我们如果再想买电脑,就不是直接跟电脑厂家交易了,而是代理商跟生产厂家进行联系,我们再跟代理商进行交易。对商品的售后,也不再是买家跟厂家进行联系了,而是买家跟代理商联系了。对于买家而言,这个中间商就是对生产厂家进行了代理。

静态代理

要说动态代理,有必要先了解下静态代理,静态代理动态代理的主要区别前者的代理类需要程序员手动编码,而后者的代理类是自动生成的。
代码实现

  1. 创建IProducer接口,定义销售商品规范
public interface IProducer {
    /**
     * 销售商品
     * @param maney
     */
    void sale(float maney);
}
  1. 创建Producer类,定义生产厂家
public class Producer implements IProducer {
    public void sale(float maney) {
        System.out.println("销售了商品,并拿到了钱:"+maney);
    }
}
  1. 创建StaticProxy类,定义静态代理类
public class StaticProxy implements IProducer {
    private IProducer producer;
    public StaticProxy(IProducer producer){
        this.producer=producer;
    }
    public void sale(float maney) {
        producer.sale(maney*0.8f);
    }
}
  1. 测试(我这里使用的是单元测试,需要导入Juni依赖)
public class TestStaticProxy {
    IProducer producer=new Producer();
    StaticProxy staticProxy=new StaticProxy(producer);
    @Test
    public void TestStaticProxy(){
        //用户直接通过代理商购买商品,花了10000块,
        // 生产厂家得到了8000块,还有2000块是代理商的活动经费
        //毕竟人家也要吃饭嘛
        staticProxy.sale(10000f);
    }
}

控制台打印信息:销售了商品,并拿到了钱:8000.0

JDK动态代理机制

代码实现

  1. 创建一个JDKDynamicProxy类,用来获取代理类对象
public class JDKDynamicProxy {
    IProducer producer=new Producer();
    /**
     * 获取动态代理类对象
     * @return
     */
    public IProducer getProxy(){
        IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Float money = (Float) args[0];
                        method.invoke(producer,money*0.8f);
                        return null;
                    }
                });
        return proxyProducer;
    }
}
  • 要求
    被代理类至少实现一个接口
  • 创建方式
    Proxy.newProxyInstance(三个参数)
  • newProxyInstance方法三个参数
    ClassLoader:和被代理对象使用相同的类加载器
    Interface:和被代理对象具有相同的行为,实现相同的接口
    InvocationHandler:如何代理
  • InvocationHandler中的invoke方法详解
    执行被代理对象的任何方法都会经过该方法
    参数:
    proxy:代理对象的引用
    method:当前执行的被代理对象的方法的方法对象
    args:执行被代理对象的方法所需的参数
    返回值:当前执行的被代理对象的方法的返回值
  1. 测试
public class TestJDKDynamicProxy {
    JDKDynamicProxy jdkDynamicProxy=new JDKDynamicProxy();
    @Test
    public void testJDKDynamicProxy(){
        //获取代理对象
        IProducer proxyProducer = jdkDynamicProxy.getProxy();
        //执行此方法最终会执行InvocationHandler的的invoke方法
        proxyProducer.sale(10000f);
    }
}

控制台打印信息:销售了商品,并拿到了钱:8000.0
3. JDK动态代理的缺陷

  • 被代理类必须实现接口
  • 如果被代理类实现多个接口,在创建代理类对象时应该转向哪个类型
    正是由于有这么多缺陷,于是有了CGLib动态代理

CGLib动态代理

  1. 要使用CGLib动态代理需要引入第三发依赖
<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.5</version>
        </dependency>
  1. 创建CGLibProxy类,来获取代理对象
public class CGLibProxy {
    Producer producer=new Producer();
    public Producer getProxy(){
        Producer proxyProducer  = (Producer) Enhancer.create(this.producer.getClass(), new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Float money = (Float) objects[0];
                method.invoke(CGLibProxy.this.producer, money*0.8f);
                return null;
            }
        });
        return proxyProducer;
    }
}
  • 要求
    被代理类不能是最终类
  • 用到的类
    Enhancer
  • 用到的方法
    create(Class,Callback)
  • 方法参数
    Class:被代理类字节码
    Callback:如何代理
  1. 测试
public class TestCGLibProxy {
    CGLibProxy cgLibProxy=new CGLibProxy();
    @Test
    public void testCGLibProxy(){
        Producer proxyProducer = cgLibProxy.getProxy();
        proxyProducer.sale(12000f);
    }
}

控制台打印销售了商品,并拿到了钱:9600.0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值