• 动态代理


    一、类加载器

           1.类加载器的作用

       

           2.类加载器的分类

              类加载器有三种,不同类加载器加载不同的

             1)BootStrap:引导类加载器:加载都是最基础的文件

             2)ExtClassLoader:扩展类加载器:加载都是基础的文件

             3)AppClassLoader:应用类加载器:三方jar包和自己编写java文件

          3.获得类加载器

              字节码对象.getClassLoader();

    public class Demo {
            
        public static void main(String[] args) {
            Class clazz=Demo.class;  //获得Demo的字节码对象
            ClassLoader classLoader = clazz.getClassLoader();//获得类加载器
            //getResource的参数路径相对classes(src)
            classLoader.getResource("database.properties");//获得classes(src)下的任何资源
            
        }

    二、动态代理

      1.什么是动态代理(中介)

        

     调用对象(需要租房的人)----->代理对象(中介)------>目标对象(房主)

       

     2.动态代理

                  不用手动编写一个代理对象,不需要一一编写与目标对象相同的方法,这个过程,在运行时的内存中动态生成代理对象。------字节码对象级别的代理对象

      分类:

                基于子类的动态代理

                基于接口的动态代理

       1)基于接口的动态代理的:       

          * 动态代理的API:Proxy中存在一个生成动态代理的的方法newProxyInstance

          

                返回值:Object就是代理对象;

               参数:loader:代表与目标对象相同的类加载器-------目标对象.getClass().getClassLoader();

                interfaces:代表与目标对象实现的所有的接口字节码对象数组;

                h:具体的代理的操作,InvocationHandler接口

      步骤:

                   1.代理对象和真实对象实现相同的接口;

                   2.代理对象=proxy.newProxyInstance();

                   3.使用代理对象调用方法

                   4.增强方法; 方式:1.增强参数列表;2.增强返回值类型;3.增强方法体执行逻辑  

    案例:

          用户------------------->>  代理商(代理对象) --------------->联想公司(真实对象)

    //目标对象的接口
    
    public interface SaleComputer {
           
        public String sale(double money);
    
    }
    /**
     * 目标类
     */
     public class Lenovo implements SaleComputer{
         
    
        @Override
        public String sale(double money) {
            System.out.println("花了"+money+"元买了一台电脑");
            return "联想电脑";
        }
    
    
    }
    /**
     * 代理类
     * 
     * @author 撑起一片阳光
     *
     */
    public class MyAnnoTest {
        public static void main(String[] args) {
             Lenovo lenovo = new Lenovo ();
            /**
             * 三个参数: 1.类加载器:真实对象.getClass.getClassLoader 
                      * 2.接口数组: 真实对象.getClass.getInterface
                      * 3.处理器:new InvocationHandler() 
                      * 此方法返回一个代理对象,然后转成和目标对象相同的接口
             */
            SaleComputer proxy = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(),
                    lenovo.getClass().getInterfaces(),
    
                    new InvocationHandler() {
                        /**
                         * 代理逻辑编写的方法:代理对象调用的所有方法都会触发改方法执行 参数: 1.proxy:代理对象(不用) 
                                             * 2.method:代理对象调用的方法,被封装为对象
                         * 3.args:代理对象调用方法时传入的参数
                         */
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //                        System.out.println("该方法执行了");
    //                        System.out.println(method.getName());//返回sale
    //                        System.out.println(args[0]);//8000
                            
                            if (method.getName().equals("sale")) {
                                // 获取到该方法的参数
                                // 1.增强参数
                                double money = (double) args[0];
                                //3.增强方法体
                                System.out.println("专车接你去买电脑");
                                money = money * 0.85; // 参数值修改后代理对象回扣1200返回6800给真实对象
                                System.out.println("免费送货");
                                // 使用真实对象调用该方法
                                Object obj = method.invoke(lenovo , money);
                                //增强返回值
                                return obj+"+鼠标";
                            } 
                            else {
                                Object obj = method.invoke(lenovo , args);
                                return obj;
                            }
                        }
                    });
    
            // 3.调用方法
            String sale = proxy.sale(8000);//用户花了8000
            System.out.println(sale);
        }
    }

           2)基于子类的动态代理

                    涉及的类:Enhancer

                    提供者:第三方的cglib库

               * 创建代理对象:使用Enhancer类中的create方法

                 注意:代理的类不能为最终类   

    实现步骤:

                  第一步:导入依赖        

    <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.1_3</version>
        </dependency>

              第二步:实现:

                

    **
     * 生产者,要代理的类
     */
    public class Produce {
        /**
         * 销售
         * @param money
         */
        public void saleProduce(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 Produce produce = new Produce();
            /**
             * 动态代理
             *   creat方法参数:
             *            Class:字节码
             *                它是用于指定被代理对象的字节码
             *            Callback:用于提供增强的代码
             *                它是用于我们写如何代理,一般都写一个该接口的实现类,通常情况下都是匿名但不必须
             *                此接口的实现类谁用谁写
             *                一般写该接口的子接口实现类类,MethodInterceptor
             */
            Produce cglibProduce= (Produce) Enhancer.create(produce.getClass(), new MethodInterceptor() {
                /**
                 * 执行被代理对象的任何方法都会经过该方法
                 *
                 * @param proxy
                 * @param method
                 * @param args                    以上的三个参数和基于接口的中invoke方法的参数一样
                 * @param methodProxy:当前执行方法的代理对象
                 * @return
                 * @throws Throwable
                 */
                @Override
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    //增强的代码
                    Object returnValue = null;
                    //1.获取方法执行参数
                    Float money = (Float) args[0];
                    //2.判断当前方法是不是销售
                    if ("saleProduce".equals(method.getName())) {
                        returnValue = method.invoke(produce, money * 0.8f);
    
                    }
                    return returnValue;
                }
            });
            cglibProduce.saleProduce(15555f);
        }
    }
    
    
    
     

             

  • 相关阅读:
    js学习总结----js中的三个判断
    js学习总结----js中的变量和数据类型
    js学习总结---js组成和命名规范
    ES6-----学习系列十八(模块化)
    ES6-----学习系列十七(Decorator)
    ES6-----学习系列十六(Generator)
    迭代器和for-of循环 顺便带一下Es5中的.map遍历
    Pc端css初始化
    css3常用属性
    css布局一屏幕的自适应高度
  • 原文地址:https://www.cnblogs.com/cqyp/p/12463299.html
Copyright © 2020-2023  润新知