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

    什么是动态代理:

    举个小例子:假如我们要买电脑,如果没有代理,我们会直接找生产厂家购买;

    但现在是:代理商找厂家进货,我们是找代理商购买。

    用代码讲一下:

    一、基于接口的动态代理

    1、直接联系生产厂家

    IProduce.java


    package
    com.henu.proxy;

    //对生产厂家要求的接口
    public interface IProducer { public void sale(float money); public void afterSale(float money); }

    Produce.java

    package com.henu.proxy;
    
    //一个生产者
    public class Producer implements IProducer{
    
        public void sale(float money) {
            System.out.println("卖出一台电脑,收   "+money);
        }
        public void afterSale(float money) {
            System.out.println("修理一台电脑,收   "+money);
        }
    }

    Client.java

    package com.henu.proxy;
    
        //模拟一个消费者
        public class Client {
    
    
            public static void main(String[] args) {
                Producer producer = new Producer();
    
                producer.sale(10000f);
            }
        }

    假如使用基于接口的动态代理:只需要对Client.java进行修改:

    package com.henu.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方法
            *   创建代理对象的要求:
            *       被代理对象最少实现一个接口,如果没有,则不能用
            *   new ProxyInstance方法的参数:
            *       ClassLoader:类加载器
            *           它用于加载代理对象的字节码。和被代理对象使用相同的类加载器。(固定写法)
            *       Class[]:字节码数组
            *           它用于让代理对象和被代理对象有相同的方法。 (固定写法)
            *       InvocationHandler:用于增强的代码
            *            它是让我们写如何代理。我们一般都是写一个接口的实现类,通常情况下是匿名内部类,但不是必须的。
            *             此接口的实现类是谁用谁写。
            *
            *
            */
            IProducer poxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                    producer.getClass().getInterfaces(), new InvocationHandler() {
                        /**
                         *作用:执行被代理对象的任何接口方法都会经过该方法
                         *方法参数的定义:
                         * @param proxy     代理对象的引用
                         * @param method    当前执行的方法
                         * @param args      当前执行方法所需的参数
                         * @return          和被代理对象方法具有相同的返回值
                         * @throws Throwable
                         */
    
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //提供增强的代码
                            Object returnValue = null;
                            //1.获取方法执行的参数
                            float money = (Float) args[0];
                            //2.判断当前方法是不是销售
                            if ("sale".equals(method.getName())){
                                returnValue = method.invoke(producer,money*0.8f);
                            }
                            return returnValue;
                        }
                    });
            poxyProducer.sale(10000f);
        }
    }

    二、基于子类的动态代理

     拷贝Produce.java类

    package com.henu.cglib;
    
    import com.henu.proxy.IProducer;
    //一个生产者
    public class Producer{
    
        public void sale(float money) {
            System.out.println("卖出一台电脑,收   "+money);
        }
        public void afterSale(float money) {
            System.out.println("修理一台电脑,收   "+money);
        }
    }

    基于子类的动态代理

    Client.java

    package com.henu.cglib;
    
    import com.henu.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方法
            *   创建代理对象的要求:
            *       被代理对象不能是最终类
            *   newProxyInstance方法的参数:
            *       Class:字节码
            *           它用于指定被代理对象的字节码
            *       Callback:用于提供增强的代码
            *           它是让我们写如何代理。我们一般都是写该接口的实现类,通常是匿名内部类,但不是必须的。
            *           此接口的实现类都是谁用谁写的
            *           我们一般写的都是该类的子接口实现类:MethodInterceptor
            */
    
            Producer cglibProduce = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    /**
                         *作用:执行被代理对象的任何接口方法都会经过该方法
                         *方法参数的定义:
                         * @param o             代理对象的引用
                         * @param method        当前执行的方法
                         * @param objects       当前执行方法所需的参数
                         * @param methodProxy   当前执行方法的代理对象
                         * @return              和被代理对象方法具有相同的返回值
                            * @throws Throwable
                            */
                    //提供增强的代码
                    Object returnValue = null;
                    //1.获取方法执行的参数
                    float money = (Float) objects[0];
                    //2.判断当前方法是不是销售
                    if ("sale".equals(method.getName())){
                        returnValue = method.invoke(producer,money*0.8f);
                    }
                    return returnValue;
                }
            });
            cglibProduce.sale(20000f);
        }
    }
  • 相关阅读:
    解决IDEA springBoot读取*.properties文件中文内容乱码的问题
    springboot读取自定义properties配置文件方法
    解决Vue调用springboot接口403跨域问题
    eclipse springboot工程打war包方法及在Tomcat中运行的方法
    Android native进程间通信实例-socket本地通信篇之——服务端进程异常退出解决办法
    Android native进程间通信实例-socket本地通信篇之——基本通信功能
    Android native进程间通信实例-binder篇之——解决实际问题inputreader内建类清楚缓存
    Android native进程间通信实例-binder篇之——用parcel传输数组
    Android native进程间通信实例-binder篇之——简单的单工通信
    解决多类开机弹框问题
  • 原文地址:https://www.cnblogs.com/qzhc/p/11966184.html
Copyright © 2011-2022 走看看