【04】Java--动态代理

【04】Java–代理模式


代理模式有两种:

  • 动态代理
  • 静态代理

通俗的说:Java里面的代理其实和生活中的代理商,代购的意思类似。假设有一个场景,里面有生产厂家,消费者,代理商。我们一般都是通过代理商进行购买的,然后代理商向厂家拿货。这就是代理

那么动态代理和静态代理有什么区别呢?

  • 动态代理没有固定的代理商,都是临时找的。
  • 静态代理的话是有一个固定的代理商。

Java里:

  • 动态代理:没有固定的类,什么时候用,什么时候创建(灵活性好
  • 静态代理:有一个固定的类,在使用代理的时候,直接通过静态工厂获取即可使用


一、静态代理:

要求

  • 代理类和被代理类需要实现相同的接口
  • 通过静态工厂向外提供代理对象

1 生产厂家接口:

package indi.indi.xu.proxy3;

/**
 * @author a_apple
 * @create 2020-01-15 15:56
 */
public interface IProducer {

    /**
     * 销售方法
     * @param money
     */
    void sale(Integer money);

    /**
     * 维修方法
     * @param money
     */
    void fix(Integer money);
}

2 生产厂家:

package indi.indi.xu.proxy3;

/**生产厂家:
 * 无代理:直接向厂家购买的话,你付多少钱,厂家就会收到多少
 *
 * 代理:你给代理钱,代理给厂家钱,赚取差价。此时厂家收到的并不是你付的所有钱
 * @author a_apple
 * @create 2020-01-15 15:56
 */
public class Producer implements IProducer{

    public void sale(Integer money) {
        System.out.println("出售一件商品,厂家获得:"+money);
    }

    public void fix(Integer money) {
        System.out.println("维修商品,厂家获得:"+money);
    }
}

3 静态代理:

里面内置了一个实现了接口的生产厂家类,并对它的方法进行增强

package indi.indi.xu.proxy3;

/**
 * 静态代理:
 *
 * @author a_apple
 * @create 2020-01-15 16:26
 */
public class StaticProxyProducer implements IProducer {

    private Producer producer;

    public StaticProxyProducer(Producer producer) {
        this.producer = producer;
    }

    public void sale(Integer money) {
        producer.sale((int) (money * 0.6));
    }

    public void fix(Integer money) {
        producer.fix((int) (money * 0.8));
    }
}

4 静态代理工厂:

package indi.indi.xu.proxy3;

/**静态工厂:
 * 客户通过静态工厂获取代理对象
 * @author a_apple
 * @create 2020-01-15 16:31
 */
public class StaticFactory {

    public static IProducer getProxyProducer(){
        return new StaticProxyProducer(new Producer());
    }
}

5 消费者:

package indi.indi.xu.proxy3;

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;

/**消费者
 *
 * 如果原厂价为6000元:
 *      直接向厂家购买:付6000
 *      通过代理购买:付10000
 * @author a_apple
 * @create 2020-01-15 16:03
 */
public class Client {

    public static final Producer producer = new Producer();

    public static void main(String[] args) {

        //直接从厂家购买
        fromProducer(6000);

        //静态代理
        fromStaticProxy(10000);
    }

    /**
     * 直接从厂家购买
     * @param money
     */
    public static void fromProducer(Integer money){
        System.out.println("直接向厂家购买:");
        System.out.println("付款:"+money);

        producer.sale(money);
    }

    /**
     * 静态代理:
     */
    public static void fromStaticProxy(int money){
        System.out.println("\n通过静态代理购买:");
        System.out.println("付款:"+money);

        IProducer proxyProducer = StaticFactory.getProxyProducer();
        proxyProducer.sale(money);
    }
}



二、动态代理:

分类、要求

  • 基于接口的动态代理:被代理类(Producer)最少实现一个接口(IProducer),如果没有则不能使用
  • 基于子类的动态代理:被代理类(Producer)不能用 final 修饰。(无法创建子类了

1 生产厂家和接口和上面一样

1-动态代理:基于接口

/**动态代理:基于接口
     *
     * 通过代理购买
     * @param money
     */
    public static void fromProducerProxy(Integer money){

        System.out.println("\n(基于接口)通过动态代理购买:");
        System.out.println("付款:"+money);

        IProducer proxyProducer = (IProducer)Proxy.newProxyInstance(
                producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object returnValue = null;
                        //1.获取方法名,判断是否是销售方法
                        if ("sale".equals(method.getName())) {
                            //2.获取方法参数
                            Integer money = (Integer) args[0];
                            //3.增强、执行方法
                            returnValue = method.invoke(producer, (int) (money * 0.6));
                        }
                        //4.返回方法返回值
                        return returnValue;
                    }
                });
        proxyProducer.sale(10000);
    }

2-动态代理:基于子类
/**
     * 动态代理:基于子类
     *
     * @param money
     */
    public static void fromSubProducerProxy(Integer money){

        System.out.println("\n(基于子类)通过动态代理购买:");
        System.out.println("付款:"+money);

        //代理对象
        Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * 作用:执行被代理对象的任何接口方法都会经过该方法
             * @param proxy     代理对象的引用(proxyProducer
             * @param method    当前执行的方法
             * @param args      当前执行方法所需的参数
             *
             * @param methodProxy   当前执行方法的代理对象(一般不用
             * @return
             * @throws Throwable   和被代理对象方法具有相同的返回值.(返回的是Objec,需要再强转一下
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //提供增强的方法
                Object returnValue = null;

                //2.获取当前方法名,判断是不是销售方法
                if("sale".equals(method.getName())){
                    //1.获取方法执行的参数
                    Integer money = (Integer)args[0];
                    returnValue = method.invoke(producer, (int) (money * 0.6));
                }
                return returnValue;
            }
        });

        cglibProducer.sale(10000);
    }

Client:

public class Client {

    public static final Producer producer = new Producer();

    public static void main(String[] args) {

        //直接从厂家购买
        fromProducer(6000);

        //动态代理-基于接口
        fromProducerProxy(10000);

        //动态代理-基于子类
        fromSubProducerProxy(10000);

        //静态代理
        fromStaticProxy(10000);
    }

   ....
}

结果:

直接向厂家购买:
付款:6000
出售一件商品,厂家获得:6000

(基于接口)通过动态代理购买:
付款:10000
出售一件商品,厂家获得:6000

(基于子类)通过动态代理购买:
付款:10000
出售一件商品,厂家获得:6000

通过静态代理购买:
付款:10000
出售一件商品,厂家获得:6000



三、两种代理的比较:

  • 当一个实现不同接口的对象需要代理时,静态代理实现时需要对每个接口编写一个代理类。所以当接口比较多的时候,静态代理就不合适了
  • 动态代理可以通过对生成代理类方法的调用,传入需要实现的接口,动态生成实现不同接口的代理类,操作方便。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值