动态代理实现的两种方式

动态代理知识详解-LMLPHP

给动态代理举个栗子:例如我们平时买笔记本电脑,很多时候都是不从厂家拿货,而是通过经销商买电脑。代理模式出现解决了生产厂家的一些问题,那么这个这个思想在我们编程中是怎么体现的啦???

下面根据具体的案例来解释

目录结构

动态代理知识详解-LMLPHP

1、基于接口动态代理

该方式的缺点:如果类不实现接口,代理是无法使用

* 动态代理的特点就是字节码,随用随创建,随用随加载
* 作用:在不修改源码的基础上对方法的增强
* 分类:
*      基于接口动态代理
*      基于子类的动态代理
* 基于接口的动态代理
*      涉及类:proxy
*      提供者:jdk官方
* 如何创建动态代理对象
*      使用proxy中的newProxyInstance方法
* 创建代理对象的要求:
*      被代理的对象至少实现一个接口,如果没有则不能使用
* newProxyInstance方法的参数
* classLoader  用于加载代理对象的字节码,写的是被代理对象的类加载器,和被代理对象使用相同的类加载器(固定写法)
* Class[]   它是用于代理对象和被代理对象有相同的方法(固定写法)
* InvocationHandler 用于增强的代理,含义是写如何代理,我们一般是写一个该接口的实现类,
* 通常情况下是匿名内部类(匿名内部类访问外部成员时,需要用final修饰),但是不必须,都是谁用谁写

案例如下:

接口
package com.cc.proxy;

public interface IProducer {

    public void saleProduct(float money);

    public void afterService(float money);

}
package com.cc.proxy;

/**
 * 一个生产者
 */
public class Producer implements IProducer{
    /**
     * 销售
     */
    public void saleProduct(float money){
        System.out.println("销售产品,拿到钱:"+money);
    }

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

测试方法

package com.cc.proxy;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 模拟一个消费者
 * 基于接口的动态代理,如果类不实现接口代理是无法使用
 */
public class Client {
   @Test
    public void test(){
       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
                    */
           @Override
           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(12000f);

   }
}

2、基于子类的动态代理

/**
 * 动态代理:
 *  特点:字节码随用随创建,随用随加载
 *  作用:不修改源码的基础上对方法增强
 *  分类:
 *      基于接口的动态代理
 *      基于子类的动态代理
 *  基于子类的动态代理:
 *      涉及的类:Enhancer
 *      提供者:第三方cglib库
 *  如何创建代理对象:
 *      使用Enhancer类中的create方法
 *  创建代理对象的要求:
 *      被代理类不能是最终类
 *  create方法的参数:
 *      Class:字节码
 *          它是用于指定被代理对象的字节码。
 *
 *      Callback:用于提供增强的代码
 *          它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
 *          此接口的实现类都是谁用谁写。
 *          我们一般写的都是该接口的子接口实现类:MethodInterceptor
 */
package com.cc.cglib;

/**
 * 一个生产者
 */
public class Producer {
    /**
     * 销售
     */
    public void saleProduct(float money){
        System.out.println("销售产品,拿到钱:"+money);
    }

    /**
     * 售后
     */
    public void afterService(float money){
        System.out.println("提供售后服务,并拿到钱"+money);
    }
}
package com.cc.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * 模拟一个消费者
 */
public class Client {
    @Test
    public void test(){
            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
                 */
                @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("saleProduct".equals(method.getName())){
                        returnValue=method.invoke(producer,money*0.8f);
                    }
                    return returnValue;
                }
            });
            cglibProducer.saleProduct(12000f);
        }
}

测试结果如下:

动态代理知识详解-LMLPHP

05-23 03:56