java动态代理

1.什么是动态代理

动态代理利用Java的反射技术(Java Reflection)生成字节码,在运行时创建 一个实现某些给定接口的新类(也称"动态代理类")及其实例。动态代理类负责给被代理类处理或者过滤消息,来实现对方法的增强。

2.动态代理的特点

1.字节码随用随创建,随用随加载,它与静态代理的区别就在于此,因为静态代理是字节码一上来就创建好,并完成加载,装饰者模式就是静态代理的一种体现

2.1动态代理常用的两种方式

2.1.1 基于接口的动态代理

提供者:JDK官方的Proxy类
要求:被代理类最少实现一个接口

2.1.2 基于子类的动态代理

提供者:第三方的CGLIB,需要导入坐标。
要求:被代理类不能用final修饰的类

3.动态代理例子:

此处用一个电脑生产厂家,代理商,用户的例子,在十几年前的时候,电脑生产厂家为了卖出电脑,基本上都是在某个商场租一层楼来专门去销售它的电脑,然后用户呢就直接找厂家购买电脑,然后厂家也会对电脑做一个售后,但是随着经济以及时代的发展,厂家就觉得负责这两件事情可能忙不过来了,假如说生产一万台电脑,就要准备一个能放一万台电脑的库房,这个时候还得去雇佣销售人员,这个时候厂家的运营成本就明显上升了,然后这个时候就出现了代理商(负责对产品的销售及售后),而作为我们用户就直接找经销商去买电脑了,如果电脑出问题了,则联系经销商,经销商则联系厂家。这样就降低了厂商的运营成本。
通过以上分析,代理的方式解决了生产厂家的一些问题,在java程序中也是如此。

3.1基于接口实现动态代理

如何创建代理对象:
     *   使用Proxy中的newProxyInstance方法
     *  创建代理对象的要求:
     *   被代理类最少实现一个接口,如果没有则不能使用
     *  newProxyInstance 方法的参数
     *  ClassLoder:类加载器
     *    它是用于加载代理对象的字节码的,和被代理对象使用相同的类加载器,固定写法
     *  Class[]:字节码数组
     *   它是用于让代理对象和被代理对象有相同的方法,固定写法
     *  InvocationHandler
     *  用于提供增强的代码
     *  它是让我们写如何代理,我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的
     *  此接口的实现类都是谁用谁写

代码如下:

/**
 * 对生产厂家要求的接口
 */
public interface IProducer {

    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money);
    /**
     * 售后
     * @param money
     */
    public void afterService(float money);
}
/**
 * 生产商的实现类
 */
public class Producer implements IProducer {

    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money)
    {
        System.out.println("销售产品,并拿到钱"+money);
    }

    /**
     * 售后
     * @param money
     */
   public void afterService(float money)
   {
       System.out.println("售后服务,并拿到钱"+money);
   }
}

/**
 * 模拟一个消费者
 */
public class Client {
    public static void main(String[] args) {
//        匿名内部类访问外部成员变量时,要求是最终的
        final Producer producer = new Producer();
         IProducer proxyProducer =(IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(), new InvocationHandler() {
                     /**
                      * 作用:
                      * 执行被代理对象的任何接口方法都会经过该方法
                      * 方法参数的含义:
                      * @param proxy 代理对象的引用
                      * @param method 当前执行的方法
                      * @param args 当前执行方法所需的参数
                      * @return 和被代理对象有相同的返回值
                      * @throws Throwable
                      */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //提供增强的代码
                        Object returnValue = null;
                        //1.获取方法执行的参数
                        float money =(Float)args[0];
                        //2.判断当前方法是不是销售
                        if("saleProduct".equals(method.getName()))
                        {
                           returnValue = method.invoke(producer,money*0.8f);
                        }
                        return returnValue;
                    }
                });
        proxyProducer.saleProduct(10000f);
    }
}

运行结果如下(假设代理商抽成百分之二十)
在这里插入图片描述

3.2 基于子类的动态代理

        如何创建代理对象:
     * 使用Enhancer中的create方法
     *  创建代理对象的要求:
     *  被代理类不能是最终类
     
     *  create()方法的参数
     *  Class:字节码
     *  它是用于指定被代理对象的字节
     *  callback
     *  用于提供增强的代码
     *  我们一般写的都是该接口的子接口实现类,MethodInterceptor(方法拦截)

首先导入cglib的坐标
在这里插入图片描述

/**
 * 生产商
 */
public class Producer  {

    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money)
    {
        System.out.println("销售产品,并拿到钱"+money);
    }

    /**
     * 售后
     * @param money
     */
   public void afterService(float money)
   {
       System.out.println("售后服务,并拿到钱"+money);
   }
    
}
public class Client {
    public static void main(String[] args) {
//        匿名内部类访问外部成员变量时,要求是最终的
        final Producer producer = new Producer();
      Producer cglibProducer  =(Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * 执行被代理对象的任何方法都会经过该方法
             * @param proxy
             * @param method
             * @param args
             * 以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
             * @param methodProxy
             * @return
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //提供增强的代码
                Object returnValue = null;
                //1.获取方法执行的参数
                float money =(Float)args[0];
                //2.判断当前方法是不是销售
                if("saleProduct".equals(method.getName()))
                {
                    returnValue = method.invoke(producer,money*0.8f);
                }
                return returnValue;
            }
        });
        cglibProducer.saleProduct(10000f);

    }
}

结果和上图一样

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值