• 1、代理模式


    二、结构型模式

        1、代理模式

            (1)、概述

                代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:在不改动原有代码的前提下,在已有代码基础上添加新的功能,从而增强原功能。这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。

            (2)、分类

                ①、静态代理(静态定义代理类):静态代理实现起来比较简单,需要提前定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。但静态代理需要去实现每一个被代理的类以及方法,如果被代理的方法比较多,会比较繁琐。

                ②、动态代理(动态生成代理类):

                    a、JDK动态代理:需要被代理类一定要实现某个接口,而代理类只需要实现InvocationHandler接口。代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。只能对实现了接口的类生成代理,而不能针对类,对于没有实现接口的类无法实现JDK动态代理。Spring会使用JDK Proxy去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Proxy去进行代理,因为Proxy.newProxyInstance()方法会返回的是一个指定接口的代理类实例,需要用接口接收。

                    b、cglib动态代理:提供的动态代理不需要类实现了某个接口,是针对类实现代理。cglib采用继承的方式实现动态代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。

            (3)、静态代理的代码实现

                ①、定义Automobile接口

    public interface Automobile {

        String doSomething(String series);

    }

                ②、被代理类实现Automobile接口

    public class Benz implements Automobile {

        @Override

        public String doSomething(String series) {

            return String.format("德国奔驰:%s",series);

        }

    }

                ③、代理类实现Automobile接口

    public class BeijingBenz implements Automobile {

        private Benz benz;

        public BeijingBenz(Benz benz){

            this.benz = benz; 

        }

        @Override

        public String doSomething(String series) {

            System.out.println("我是北京奔驰,我代理德国奔驰");

            String msg =  benz.doSomething(series);

            System.out.println(msg);

            return msg;

        }

    }

                ④、实现静态代理

    public class Main {

        public static void main(String[] args) {

            Benz benz = new Benz();

            BeijingBenz beijingBenz = new BeijingBenz(benz);

            beijingBenz.doSomething("S600");

        }

    }

                ⑤、实际应用

                    TokenCallable通过代理Callable实现token的传递,以及日志打印的一些信息。

    public class TokenCallable implements Callable {

        private final String accessToken;

        /**

         * 被代理的Callable

         */

        private final Callable delegate;

        private final String taskName;

        public TokenCallable(Callable delegate, String accessToken,String taskName) {

            this.delegate = CallableWrapper.of(delegate);

            this.accessToken = accessToken;

            this.taskName = taskName;

        }

        @Override

        public V call() throws Exception {

           long start = System.currentTimeMillis();

            LogUtil.debug("currentThreadId = " + Thread.currentThread().getId() + ",accessToken=" + accessToken);

            //给当前线程设置token

            AccessTokenUtil.setAccessToken(accessToken);

            V call = delegate.call();

            LogUtil.info("taskName =" + taskName + ",taskTime = " + (System.currentTimeMillis() - start) + " ms");

            return call;

        }

    }

            (4)、JDK动态代理的代码实现

                ①、定义Automobile接口

    public interface Automobile {

        String doSomething(String series);

    }

                ②、被代理类实现Automobile接口

    public class BMW implements Automobile {

        @Override

        public String doSomething(String series) {

            return String.format("德国宝马 %s", series);

        }

    }

                ③、代理类实现InvocationHandler接口

    public class HuachenBMW implements InvocationHandler {

        public Automobile target;

        public HuachenBMW(Automobile target) {

            this.target = target;

        }

        @Override

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            System.out.println("来中国混,根据指示找代理");

            Object ret = method.invoke(target, args);

            System.out.println("代理车系是:" + ret);

            return ret;

        }

    }

                ④、实现JDK动态代理

    public class Main {

        public static void main(String[] args) {

            BMW BMW = new BMW();

            HuachenBMW huachenBMW = new HuachenBMW(BMW);

            //通过Proxy.newProxyInstance()方法返回一个指定接口的代理类实例

            Automobile automobile = (Automobile)Proxy.newProxyInstance(BMW.getClass().getClassLoader(),

                    BMW.getClass().getInterfaces(),

                    huachenBMW);

            String series = automobile.doSomething("X6");

            System.out.println("抢到一辆:"+ series);

        }

    }

            (5)、cglib动态代理的代码实现

                ①、引入cglib的jar包

        cglib

        cglib

        3.2.10

                ②、定义被代理类

    public class Audi {

        public String doSomething(String series){

            System.out.println("原产于德国的奥迪汽车");

            return String.format("德国奥迪,车系是:%s", series);

        }

    }

                ③、代理类实现MethodInterceptor接口

    public class FirstAudi implements MethodInterceptor {

        @Override

        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

            System.out.println("代理德国奥迪汽车");

            Object series =  methodProxy.invokeSuper(o, objects);

            System.out.println(series);

            return series;

        }

    }

                ④、实现cglib动态代理

    public class Main {

        public static void main(String[] args) {

            Enhancer enhancer = new Enhancer();

            enhancer.setSuperclass(Audi.class);

            enhancer.setCallback(new  FirstAudi());

            Audi audi = (Audi) enhancer.create();

            audi.doSomething("A8");

        }

    }

            注:JDK内置动态代码采用Java反射机制实现,cglib库实现的动态代理,采用的是ASM直接操作字节码方式实现。由于反射操作的效率要低于直接操作字节码的效率,所以,cglib实现动态代理效率上比JDK内置的动态代理要好。

  • 相关阅读:
    Polygon zkEVM 基本概念
    (树) 树状数组
    【蓝桥杯2025备赛】素数判断:从O(n^2)到O(n)学习之路
    第 372 场 LeetCode 周赛题解
    【云原生kubernetes从入门到实践系列教程 ] 四.docker volumes持久化
    【Unity Texture】_MainTex的含义
    .NET JIT
    基于PHP+MYSQL在线小说阅读网的设计与实现
    Redis—List数据类型及其常用命令详解
    CDR最新CorelDRAWX8安装步骤教程
  • 原文地址:https://blog.csdn.net/L_D_Y_K/article/details/126837087