zoukankan      html  css  js  c++  java
  • Java动态代理

    代理在日常生活中很常见,例如:一个手机生产厂家,需要提供生产,销售,以及售后等多种服务,但是,作为生产厂家并没有足够的精力又做生产,又做销售,又做售后。此时便诞生了很多的手机销售代理商,他们从成产厂家拿货后实现销售、以及售后功能,这就是代理,在程序中也是也较为常见的代理模式。

    分析以上过程,可知,代理商实际上和厂家实际上都实现了一套规则,就是销售和售后功能,代理商实现厂家所要实现的服务,并从服务中抽取部分利润,所以在程序中可用代理实现对一些服务功能做增强来实现;

    Java动态代理的分为基于接口的动态代理基于子类的动态代理

    如下代码是基于接口的动态代理

    先编写一个代理对象和被代理对象都要实现的一致接口,即生产厂家和代理商都要实现的销售和售后服务

    package cn.blogsx.proxy;
    
    /**
     * 对生产厂家的接口
     */
    public interface IProducer {
        //销售
        public void sellProduct(float money);
    
        //售后
        public void afterService(float money);
    }
    
    

    在编写一个被代理类,即生产厂家,

    package cn.blogsx.proxy;
    
    /**
     * 一个生产厂家
     */
    public class Producer implements IProducer {
        //销售
        public void sellProduct(float money) {
            System.out.println("销售产品:拿到钱:" + money);
        }
    
        //售后
        public void afterService(float money) {
            System.out.println("提供售后服务,并拿到钱:"+money);
        }
    }
    

    编写一个代理商,生产厂家的销售和售后功能被代理商 代理实现

    package cn.blogsx.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 模拟一个代理商
     */
    public class Client {
        public static void main(String[] args) {
            final Producer producer = new Producer();
            /**
             * 动态代理:
             *    特点:  字节码随用随创建
             *    作用:   不修改源码的基础上对方法增强
             *
             分类:
             *      基于接口的动态代理
             *      基于子类的动态代理
             *  基于接口的动态代理:
             *      涉及的类:Proxy
             *      提供者:JDK官方
             *  如何创建代理对象:
             *      使用Proxy类中的newProxyInstance方法
             *  创建代理对象的要求:
             *      被代理类最少实现一个接口,如果没有则不能使用
             *  newProxyInstance方法的参数:
             *      ClassLoader:类加载器
             *          它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
             *      Class[]:字节码数组
             *          它是用于让代理对象和被代理对象有相同方法。固定写法。
             *      InvocationHandler:用于提供增强的代码
             *          它是让我们写如何代理。我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
             *          此接口的实现类都是谁用谁写。
             *
             *
             */
    
            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("sellProduct".equals(method.getName())){
                               returnValue = method.invoke(producer, money*0.8F);
                            }
                            return returnValue;
    
                        }
    
                    });
    
            proxyProducer.sellProduct(1000F);
        }
    }
    
    

    运行结果:

    销售产品:拿到钱:800.0
    
    Process finished with exit code 0
    

    可以看到,代理商和厂商都实现了一个统一的接口,好比生活中厂家和代理商签好的合同约定,厂家将具体的面向市场消费者所需的销售和售后服务交给代理商实现,而代理商实现预定的服务并从中抽取部分利润,如代理商销售一部千元手机,而和厂家约定是每销售部门手机提成20%,那么对于厂家来说,最后拿到的销售金额为800元。也就是我们在程序中对一些指定的方法做了增强,并且在不改变源码的基础上做出了增强。

    基于子类的动态代理

    由于JDK没有提供基于子类的动态代理接口方法,所以需要基于第三方库cglib来实现:

    被代理类:

    package cn.blogsx.cglib;
    
    import cn.blogsx.proxy.IProducer;
    
    /**
     * 一个生产者
     */
    public class Producer {
        //销售
        public void sellProduct(float money) {
            System.out.println("销售产品:拿到钱:" + money);
        }
    
        //售后
        public void afterService(float money) {
            System.out.println("提供售后服务,并拿到钱:"+money);
        }
    }
    
    

    代理类:

    package cn.blogsx.cglib;
    
    import cn.blogsx.proxy.IProducer;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 模拟一个消费者
     */
    public class Client {
        public static void main(String[] args) {
           final Producer producer = new Producer();
            /**
             * 动态代理:
             *  特点:字节码随用随创建,随用随加载
             *  作用:不修改源码的基础上对方法增强
             *  分类:
             *      基于接口的动态代理
             *      基于子类的动态代理
             *  基于子类的动态代理:
             *      涉及的类:Enhancer
             *      提供者:第三方cglib库
             *  如何创建代理对象:
             *      使用Enhancer类中的create方法
             *  创建代理对象的要求:
             *      被代理类不能是最终类
             *  create方法的参数:
             *      Class:字节码
             *          它是用于指定被代理对象的字节码。
             *
             *      Callback:用于提供增强的代码
             *          它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
             *          此接口的实现类都是谁用谁写。
             *          我们一般写的都是该接口的子接口实现类:MethodInterceptor
             */
           Producer cglibProxy =(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("sellProduct".equals(method.getName())){
                        returnValue = method.invoke(producer, money*0.8F);
                    }
                    return returnValue;
                }
            });
    
            cglibProxy.sellProduct(10000F);
        }
    }
    
    

    基于子类的动态代理不需要实现统一的接口,而是通过创建实现父类的动态代理子类实现对每个被代理类的增强。

  • 相关阅读:
    基于docker安装pxc集群
    PXC集群的概述及搭建
    十,StatefulSet简介及简单使用
    九,configMap及secret的基本使用
    八,kubernetes集群存储卷基础。
    七,ingress及ingress cluster
    六,k8s集群service资源
    mysql的优化
    ORACLE11g:No Dialect mapping for JDBC type: -9解决方案
    Oracle数据库的分页
  • 原文地址:https://www.cnblogs.com/sxblog/p/13194097.html
Copyright © 2011-2022 走看看