• 代理模式


    讲代理模式之前,我们要先明白什么是“代理”

    代理:简单来说就是将事情交给代替你去处理

    代理分为 静态代理动态代理

    静态代理

    直接为每一个实现类写一个代替类

    接口:

    public interface IMath {
        int add(int n1, int n2);
    
        int sub(int n1, int n2);
    
        int mut(int n1, int n2);
    }

    实现类:

    package com.nf147.ssm.springAOP.service;
    
    public class Math implements IMath {
        @Override
        public int add(int n1, int n2) {
            int result = n1 + n2;
            System.out.println(n1 + "+" + n2 + "=" + result);
            return result;
        }
    
        @Override
        public int sub(int n1, int n2) {
            int result = n1 - n2;
            System.out.println(n1 + "-" + n2 + "=" + result);
            return result;
        }
    
        @Override
        public int mut(int n1, int n2) {
            int result = n1 / n2;
            System.out.println(n1 + "/" + n2 + "=" + result);
            return result;
        }
    }

     代理类:

    package com.nf147.ssm.springAOP.proxy;
    
    import com.nf147.ssm.springAOP.service.IMath;
    import com.nf147.ssm.springAOP.service.Math;
    
    import java.util.Random;
    
    // IMath的静态代理类
    public class MathProxy implements IMath {
    
        IMath iMath = new Math();
    
        @Override
        public int add(int n1, int n2) {
            long start = System.currentTimeMillis();
            lazy();
            int result = iMath.add(n1, n2);
            Long span =  System.currentTimeMillis() - start;
            System.out.println("共用时:" + span);
            return result;
        }
    
        @Override
        public int sub(int n1, int n2) {
            long start = System.currentTimeMillis();
            lazy();
            int result = iMath.sub(n1, n2);
            Long span =  System.currentTimeMillis() - start;
            System.out.println("共用时:" + span);
            return result;
        }
    
        @Override
        public int mut(int n1, int n2) {
            long start = System.currentTimeMillis();
            lazy();
            int result = iMath.mut(n1, n2);
            Long span =  System.currentTimeMillis() - start;
            System.out.println("共用时:" + span);
            return result;
        }
    
        // 人为延时
        public void lazy(){
            try {
                int n = (int)new Random().nextInt(500);
                Thread.sleep(n);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    测试:

    // 静态代理
    IMath math = new MathProxy();
    @org.junit.Test
    public void test01() {
       int n1 = 100, n2 = 5;
       math.add(n1, n2);
       math.sub(n1, n2);
       math.mut(n1, n2);
    }

    结果:

     

     这种模式的优点:客户端不需要知道实现类是什么,怎么做的,只需要知道代理就可以了

    缺点:代理类和委托类继承了相同的接口,代理类通过委托类实现了相同的方法,使得出现了大量重复的代码,

    如果接口增加一个方法,那么不仅仅是实现类要去实现这个方法,所有的代理类也要去实现这个方法,这就增加了代码的复杂度;

    动态代理

    动态代理又分为:JDK代理对象CGLib代理对象

    JDBK代理对象:是java.lang.reflect.*包提供的方式,它必须借助于一个接口才能产生代理对象

    代理类:

    package com.nf147.ssm.springAOP.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Random;
    
    // 动态代理类
    public class DynamicProxy implements InvocationHandler {
    
        Object object;
    
        public Object getProxyObject(Object object){
            this.object = object;
            return Proxy.newProxyInstance(
                    object.getClass().getClassLoader(),
                    object.getClass().getInterfaces(),
                    this
            );
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            long start = System.currentTimeMillis();
            lazy();
            Object result = method.invoke(object,args);
            Long span = System.currentTimeMillis() - start;
            System.out.println("共用时:" + span);
            return result;
        }
    
        // 模拟延时
        public void lazy(){
            try {
                int n = (int)new Random().nextInt(500);
                Thread.sleep(n);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    测试:

    // 动态代理
        IMath math2 = (IMath) new DynamicProxy().getProxyObject(new Math());
        @org.junit.Test
        public void test02() {
            int n1 = 100, n2 = 5;
            math2.add(n1, n2);
            math2.sub(n1, n2);
            math2.mut(n1, n2);
        }

    结果:

     因为 JDK 动态代理必须要提供接口才能使用,在一些不能提供接口的环境中,它就不适用了

    CGLIb动态代理

    它是一个开源项目,是一个强大的,高性能的,高质量的Code生成类库,它可以在运行期扩展 Java 类和实现 Java 接口,

    通俗说 cglib 可以在运行时动态生成字节码。

    在使用前,要先去 https://mvnrepository.com/artifact/cglib/cglib/3.2.4 添加 cglib 包

    <!-- https://mvnrepository.com/artifact/cglib/cglib -->
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.2.4</version>
    </dependency>

     代理类:

    package com.nf147.ssm.springAOP.proxy;
    
    
    import net.sf.cglib.proxy.Callback;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    import org.aopalliance.intercept.MethodInvocation;
    
    import java.lang.reflect.Method;
    import java.util.Random;
    
    // CGLib
    // 动态代理类
    public class CGLibProxy implements MethodInterceptor {
    
        // 被代理的对象
        Object object;
    
        public Object getObject(Object object) {
            this.object = object;
            // 增强器,动态代码生成器
            Enhancer enhancer = new Enhancer();
            // 回调方法
            enhancer.setCallback((Callback) this);
            // 设置生成类的父类类型
            enhancer.setSuperclass(object.getClass());
            // 动态生成字节码并返回代理对象
            return enhancer.create();
        }
    
        // 拦截方法
        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            long start = System.currentTimeMillis();
            lazy();
    
            // 调用方法
            Object result = methodProxy.invoke(object, args);
            Long span = System.currentTimeMillis() - start;
            System.out.println("共用时:" + span);
            return result;
        }
    
        // 模拟延时
        public void lazy() {
            try {
                int n = (int) new Random().nextInt(500);
                Thread.sleep(n);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }

     测试:

    @org.junit.Test
        public void test03() {
            Math math3 = (Math) new CGLibProxy().getObject(new Math());
            int n1 = 100, n2 = 5;
            math3.add(n1, n2);
            math3.sub(n1, n2);
            math3.mut(n1, n2);
        }

     结果:

  • 相关阅读:
    vue跨域请求图片 返回前端代码无法加载图片
    神奇的选择器 :focus-within
    vue.js实现div展开收起动画
    vue+element 点击页面内跳转按钮 导航菜单选中
    css实现文本两端对齐最后一行左对齐
    鼠标拖动图片,禁止在新窗口中打开图片
    Java获取application.properties配置参数
    css处理文字不换行、换行截断、溢出省略号
    java获取当前服务器地址 例 http://localhost:xxxx
    web负载均衡
  • 原文地址:https://www.cnblogs.com/wfhking/p/10141230.html
Copyright © 2020-2023  润新知