代理模式详细学习(动态代理,静态代理)

本文详细介绍了动态代理在Java中的应用,通过JDK的Proxy和CGLIB的Enhancer,展示了如何在不修改原有代码的情况下,通过代理模式实现生产者类的净利润计算。包括基于接口的动态代理(使用IProducer接口)和基于子类的动态代理(使用Producer类)。
摘要由CSDN通过智能技术生成

0. 代理模式

  1. 作用:在不改变原来代码的基础上,对方法进行增强。

1. 动态代理

  1. 动态代理分为两种,基于接口的动态代理,基于子类的动态代理
基于接口—jdk的Proxy基于子类—cglib的Enhancer
方法Proxy.newProxyInstanceEnhancer.create
方法核心匿名内部类new InvocationHandlernew MethodInterceptor

1. 需求背景(代码演示)

  1. 先准备好一个接口,以及实现类

    		// 生产者的接口
    		public interface IProducer {
    		    void saleSomeThing(float money);
    		}
    
    		public class Producer implements IProducer {
    		
    		    @Override
    		    public void saleSomeThing(float money) {
    		        System.out.println("卖出物品,赚" + money + "元");
    		    }
    		}
    
  2. 写个测试代码,调用Producer.saleSome 得到 赚的钱:

    		public class test {
    		    public static void main(String[] args) {
    		        Producer producer = new Producer();
    		
    		        producer.saleSomeThing(1000f);
    		    }
    		}
    

    在这里插入图片描述

  3. 实际上,生产者并不会卖多少钱,赚多少钱,还需要减成本,才能得到净利润,设成本需要20%
    需求:那要如何不改原代码的基本上获取到净利润?

2. 基于接口的动态代理

  1. 先说概念:

    基于接口的动态代理:
       涉及的类:Proxy
       提供者:JDK官方
       如何创建代理对象:
          使用Proxy类中的newProxyInstance方法
       创建代理对象的要求:
          被代理类最少实现一个接口,如果没有则不能使用
       newProxyInstance方法的参数:
          ClassLoader:类加载器
             它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。
          Class[]:字节码数组,注意是接口的字节码
             它是用于让代理对象和被代理对象有相同方法。固定写法。
          InvocationHandler:用于提供增强的代码
             它是让我们写如何代理,通常情况下都是匿名内部类,但不是必须的。
    
  2. 代码演示:

    public class InterfaceProxy {
        public static void main(String[] args) {
            Producer producer = new Producer();
    		// newProxyInstance 的三个参数:
    		// 第一个:只要给类加载器就行了,你也可以写InterfaceProxy.class.getClassLoader()
    		// 第二个:字节码数组,注意是接口的字节码,也可以写成 new Class[] {IProducer.class}
    		// 第三个:用于提供增强的代码,也可以写成匿名内部类
            IProducer proxyInstance = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //proxy   代理对象的引用
                    //method  当前执行的方法
                    //args    当前执行方法所需的参数
                    if ("saleSomeThing".equals(method.getName())) {
                    		// 执行的方法是 saleSomeThing的时候,就会进入到这里,将money * 0.8 
                    		// method.invoke 执行原来方法逻辑
                        return method.invoke(producer, (float) args[0] * 0.8f);
                    }
                    // 这里写null 会出现一种现象,就是执行其他方法的时候,返回值都是null
                    return null;
                }
            });
            // 执行代理对象中的方法的时候,会先去 执行 new InvocationHandler内部类的invoke方法
            // 若要调用原来被代理对象的方法,即 需要调用 method.invoke()方法
            proxyInstance.saleSomeThing(1000f);
        }
    }
    

    在这里插入图片描述

3. 基于子类的动态代理

  1. 先说概念

    基于子类的动态代理:
       涉及的类:Enhancer
       提供者:第三方cglib库
       如何创建代理对象:
          使用Enhancer类中的create方法
       创建代理对象的要求:
          被代理类不能是最终类
       create方法的参数:
          Class:字节码
             它是用于指定被代理对象的字节码
          Callback:用于提供增强的代码
             它是让我们写如何代理。通常情况下都是匿名内部类,但不是必须的。
    
  2. 代码演示:

    public class Producer {
    	// 注意 producer 并没有实现 接口了
        public void saleSomeThing(float money) {
            System.out.println("卖出物品,赚" + money + "元");
        }
    }
    
    public class SubclassProxy {
        public static void main(String[] args) {
            Producer producer = new Producer();
            Producer producerProxy = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                		// 入参的参数都一样意思,
                		// 而methodProxy:当前执行方法的代理对象
                    Object value = null;
                    if ("saleSomeThing".equals(method.getName())) {
                        value = method.invoke(producer, (float) args[0] * 0.8f);
                    }
                    return value;
                }
            });
            producerProxy.saleSomeThing(1000f);
        }
    }
    
    

    在这里插入图片描述

2. 静态代理

  1. 概念:静态代理在使用时,需要定义接口或者父类,被代理对象(目标对象)与代理对象一起实现相同的接口或者是继承相同父类

  2. 代码例子:

    public interface IUserDao {
        void sayName(String name);
    }
    
    public class UserDao implements IUserDao{
        @Override
        public void sayName(String name) {
            System.out.println("我的名字是" + name);
        }
    }
    
    public class ProxyUserDao implements IUserDao {
    
        private IUserDao target;
    
        public ProxyUserDao(IUserDao target) {
            this.target = target;
        }
    
        @Override
        public void sayName(String name) {
            System.out.println("hello,大家早上好");
            target.sayName(name);
            System.out.println("演讲完成,大家再见");
        }
    }
    
    public class test {
        public static void main(String[] args) {
            IUserDao userDao = new UserDao();
            ProxyUserDao proxyUserDao = new ProxyUserDao(userDao);
            proxyUserDao.sayName("小明");
        }
    }
    

    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值