• 重学Android基础系列篇(三):架构动态编程技术原理


    前言

    本系列文章主要是汇总了一下大佬们的技术文章,属于Android基础部分,作为一名合格的安卓开发工程师,咱们肯定要熟练掌握java和android,本期就来说说这些~

    [非商业用途,如有侵权,请告知我,我会删除]

    DD一下: Android进阶开发各类文档/资料,也可关注公众号获取。

    1.Android高级开发工程师必备基础技能
    2.Android性能优化核心知识笔记
    3.Android+音视频进阶开发面试题冲刺合集
    4.Android 音视频开发入门到实战学习手册
    5.Android Framework精编内核解析
    6.Flutter实战进阶技术手册
    7.近百个Android录播视频+音视频视频dome
    .......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    架构动态编程技术原理

    动态编程核心架构:动态代理

    1.前言

    代理模式是一种设计模式,能够使得在不修改源目标的前提下,额外扩展源目标的功能。即通过访问源目标的代理类,再由代理类去访问源目标。这样一来,要扩展功能,就无需修改源目标的代码了。只需要在代理类上增加就可以了。

    其实代理模式的核心思想就是这么简单,在java中,代理又分静态代理和动态代理2种,其中动态代理根据不同实现又区分基于接口的的动态代理和基于子类的动态代理。

    其中静态代理由于比较简单,面试中也没啥问的,在代理模式一块,问的最多就是动态代理,而且动态代理也是spring aop的核心思想,spring其他很多功能也是通过动态代理来实现的,比如拦截器,事务控制等。

    熟练掌握动态代理技术,能让你业务代码更加精简而优雅。如果你需要写一些中间件的话,那动态代理技术更是必不可少的技能包。

    那此篇文章就带大家一窥动态代理的所有细节吧。

    2.静态代理

    在说动态代理前,还是先说说静态代理。

    所谓静态代理,就是通过声明一个明确的代理类来访问源对象。

    我们有2个接口,Person和Animal。每个接口各有2个实现类,UML如下图:

    每个实现类中代码都差不多一致,用Student来举例(其他类和这个几乎一模一样)

    public class Student implements Person{
        private String name;
    
        public Student() {
       }
    
        public Student(String name) {
            this.name = name;
        }
    
        @Override
        public void wakeup() {
            System.out.println(StrUtil.format("学生[{}]早晨醒来啦",name));
        }
    
        @Override
        public void sleep() {
            System.out.println(StrUtil.format("学生[{}]晚上睡觉啦",name));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    假设我们现在要做一件事,就是在所有的实现类调用wakeup()前增加一行输出早安~,调用sleep()前增加一行输出晚安~。那我们只需要编写2个代理类PersonProxyAnimalProxy

    PersonProxy:

    public class PersonProxy implements Person {
    
        private Person person;
    
        public PersonProxy(Person person) {
            this.person = person;
        }
    
        @Override
        public void wakeup() {
            System.out.println("早安~");
            person.wakeup();
        }
    
        @Override
        public void sleep() {
            System.out.println("晚安~");
            person.sleep();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    AnimalProxy:

    public class AnimalProxy implements Animal {
    
        private Animal animal;
    
        public AnimalProxy(Animal animal) {
            this.animal = animal;
        }
    
        @Override
        public void wakeup() {
            System.out.println("早安~");
            animal.wakeup();
        }
    
        @Override
        public void sleep() {
            System.out.println("晚安~");
            animal.sleep();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    最终执行代码为:

    public static void main(String[] args) {
        Person student = new Student("张三");
        PersonProxy studentProxy = new PersonProxy(student);
        studentProxy.wakeup();
        studentProxy.sleep();
    ​
        Person doctor = new Doctor("王教授");
        PersonProxy doctorProxy = new PersonProxy(doctor);
        doctorProxy.wakeup();
        doctorProxy.sleep();
    ​
        Animal dog = new Dog("旺旺");
        AnimalProxy dogProxy = new AnimalProxy(dog);
        dogProxy.wakeup();
        dogProxy.sleep();
    ​
        Animal cat = new Cat("咪咪");
        AnimalProxy catProxy = new AnimalProxy(cat);
        catProxy.wakeup();
        catProxy.sleep();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    输出:

    早安~
    学生[张三]早晨醒来啦
    晚安~
    学生[张三]晚上睡觉啦
    早安~
    医生[王教授]早晨醒来啦
    晚安~
    医生[王教授]晚上睡觉啦
    早安~~
    小狗[旺旺]早晨醒来啦
    晚安~~
    小狗[旺旺]晚上睡觉啦
    早安~~
    小猫[咪咪]早晨醒来啦
    晚安~~
    小猫[咪咪]晚上睡觉啦
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    结论:

    静态代理的代码相信已经不用多说了,代码非常简单易懂。这里用了2个代理类,分别代理了PersonAnimal接口。

    这种模式虽然好理解,但是缺点也很明显:

    • 会存在大量的冗余的代理类,这里演示了2个接口,如果有10个接口,就必须定义10个代理类。
    • 不易维护,一旦接口更改,代理类和目标类都需要更改。
    3.JDK动态代理

    动态代理,通俗点说就是:无需声明式的创建java代理类,而是在运行过程中生成"虚拟"的代理类,被ClassLoader加载。从而避免了静态代理那样需要声明大量的代理类。

    JDK从1.3版本就开始支持动态代理类的创建。主要核心类只有2个:java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler

    还是前面那个例子,用JDK动态代理类去实现的代码如下:

    创建一个JdkProxy类,用于统一代理:

    public class JdkProxy implements InvocationHandler {
    ​
        private Object bean;
    ​
        public JdkProxy(Object bean) {
            this.bean = bean;
        }
    ​
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            if (methodName.equals("wakeup")){
                System.out.println("早安~~~");
            }else if(methodName.equals("sleep")){
                System.out.println("晚安~~~");
            }
    ​
            return method.invoke(bean, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    执行代码:

    public static void main(String[] args) {
        JdkProxy proxy = new JdkProxy(new Student("张三"));
        Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);
        student.wakeup();
        student.sleep();
    ​
        proxy = new JdkProxy(new Doctor("王教授"));
        Person doctor = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);
        doctor.wakeup();
        doctor.sleep();
    ​
        proxy = new JdkProxy(new Dog("旺旺"));
        Animal dog = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);
        dog.wakeup();
        dog.sleep();
    ​
        proxy = new JdkProxy(new Cat("咪咪"));
        Animal cat = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);
        cat.wakeup();
        cat.sleep();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    讲解:

    可以看到,相对于静态代理类来说,无论有多少接口,这里只需要一个代理类。核心代码也很简单。唯一需要注意的点有以下2点:

    • JDK动态代理是需要声明接口的,创建一个动态代理类必须得给这个”虚拟“的类一个接口。可以看到,这时候经动态代理类创造之后的每个bean已经不是原来那个对象了。

  • 相关阅读:
    序列合并
    2022-11-14 mysql列存储引擎-subquery中出现聚合函数导致宕机-问题记录及分析
    如何设置 Git 短命令
    第九章 动态规划 part15(编辑距离专题) 392. 判断子序列 115. 不同的子序列
    netty系列之:EventExecutor,EventExecutorGroup和netty中的实现
    金仓数据库 KingbaseES 插件ftutilx
    ​辉瑞校园《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著作——2023学生开学季辉少许
    GIL全局解释器锁
    KVM 教程
    微服务治理新篇章:Eureka中细粒度策略管理实现
  • 原文地址:https://blog.csdn.net/m0_64420071/article/details/127615393