笔记 笔记
首页
  • 开发工具
  • Java Web
  • Java 进阶
  • 容器化技术
  • Java 专栏

    • Java 核心技术面试精讲
    • Java 业务开发常见错误 100 例
  • 数据库专栏

    • MySQL 实战 45 讲
    • Redis 核心技术与实战
  • 安全专栏

    • OAuth 2.0 实战课
  • 计算机系统
  • 程序设计语言
  • 数据结构
  • 知识产权
  • 数据库
  • 面向对象
  • UML
  • 设计模式
  • 操作系统
  • 结构化开发
  • 软件工程
  • 计算机网络
  • 上午题错题
在线工具 (opens new window)

EasT-Duan

Java 开发
首页
  • 开发工具
  • Java Web
  • Java 进阶
  • 容器化技术
  • Java 专栏

    • Java 核心技术面试精讲
    • Java 业务开发常见错误 100 例
  • 数据库专栏

    • MySQL 实战 45 讲
    • Redis 核心技术与实战
  • 安全专栏

    • OAuth 2.0 实战课
  • 计算机系统
  • 程序设计语言
  • 数据结构
  • 知识产权
  • 数据库
  • 面向对象
  • UML
  • 设计模式
  • 操作系统
  • 结构化开发
  • 软件工程
  • 计算机网络
  • 上午题错题
在线工具 (opens new window)

购买兑换码请添加

添加时候请写好备注,否则无法通过。

  • Maven

  • Bootstrap

  • Spring

    • Spring 概述
    • Spring 的入门
    • Spring 的工厂类
    • Spring 的 Bean
    • Spring 的依赖注入(DI)
    • 动态代理
      • 什么是动态代理
        • 基于 JDK 的动态代理
        • 基于 CGLIB 的动态代理
      • 基于接口的动态代理
      • 基于子类的动态代理
    • Spring AOP
    • Spring 的事务管理
  • Spring MVC

  • MyBatis

  • JUnit

  • GitFlow 工作流指南

  • SpringBoot

  • Reactor

  • 微服务

  • Java Web
  • Spring
EasT-Duan
2023-04-28
目录

动态代理

欢迎来到我的 ChatGPT 中转站,极具性价比,为付费不方便的朋友提供便利,有需求的可以添加左侧 QQ 二维码,另外,邀请新用户能获取余额哦!最后说一句,那啥:请自觉遵守《生成式人工智能服务管理暂行办法》。

# 动态代理

# 什么是动态代理

Spring 的动态代理是指在程序运行时动态地生成代理对象,代理对象可以在不改变原有代码的情况下增强原有代码的功能。Spring 的动态代理主要有两种方式:基于 JDK 的动态代理和基于 CGLIB 的动态代理。

# 基于 JDK 的动态代理

基于 JDK 的动态代理是指使用 Java 提供的 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来生成代理对象。JDK 动态代理只能代理实现了接口的类。

使用 JDK 动态代理时,需要定义一个 InvocationHandler 接口的实现类,该类实现 InvocationHandler 接口的 invoke 方法,代理对象的所有方法都将被重写为调用该方法。在 invoke 方法中,可以通过反射调用目标对象的方法,并在方法调用前后进行一些增强操作。

使用 JDK 动态代理的步骤如下:

  1. 定义一个 InvocationHandler 接口的实现类,实现 invoke 方法。

  2. 使用 Proxy.newProxyInstance 方法生成代理对象,该方法需要传入目标对象、目标对象的接口类型和 InvocationHandler 对象。

  3. 使用代理对象调用目标方法。

# 基于 CGLIB 的动态代理

基于 CGLIB 的动态代理是指使用 CGLIB 库来生成代理对象。CGLIB 是一个强大的高性能代码生成库,可以在运行时扩展 Java 类和实现接口。

使用 CGLIB 动态代理时,需要定义一个 MethodInterceptor 接口的实现类,该类实现 MethodInterceptor 接口的 intercept 方法,代理对象的所有方法都将被重写为调用该方法。在 intercept 方法中,可以通过反射调用目标对象的方法,并在方法调用前后进行一些增强操作。

使用 CGLIB 动态代理的步骤如下:

  1. 定义一个 MethodInterceptor 接口的实现类,实现 intercept 方法。
  2. 使用 Enhancer.create 方法生成代理对象,该方法需要传入目标对象的类类型和 MethodInterceptor 对象。
  3. 使用代理对象调用目标方法。
    总体来说,Spring 的动态代理可以很好地解耦业务逻辑和增强逻辑,使得代码更加灵活可扩展。

# 基于接口的动态代理

  • 涉及的类 proxy:提供者:jdk 官方
    • 如何创建代理对象:Proxy 中的 newInstance ()

    • 创建代理对象的要求:被代理类至少实现一个接口,如果没有则不能使用。

    • newProxyInstance 的参数

      • ClassLoader loader:写被代理类的类加载器,固定写法。

      • <bean id="exampleBean" class="org.example.hello.spring.pojo.ExampleBean">
            <property name="arrayProperty">
                <array>
                    <value>Value 1</value>
                    <value>Value 2</value>
                    <value>Value 3</value>
                </array>
            </property>
            <property name="listProperty">
                <list>
                    <value>Value 1</value>
                    <value>Value 2</value>
                    <value>Value 3</value>
                </list>
            </property>
            <property name="setProperty">
                <set>
                    <value>Value 1</value>
                    <value>Value 2</value>
                    <value>Value 3</value>
                </set>
            </property>
            <property name="mapProperty">
                <map>
                    <entry key="Key 1" value="Value 1"/>
                    <entry key="Key 2" value="Value 2"/>
                    <entry key="Key 3" value="Value 3"/>
                </map>
            </property>
        </bean>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
      • InvocationHandler h:写如何代理,通常情况下就是匿名内部类,但不是必须的。

以买电脑业务逻辑来说明

/**
 * 一个生产者
 */
public interface IProducer {
    /**
     * 销售
     *
     * @param money
     */
    public void sellProduct(Float money);

    /**
     * 售后
     *
     * @param money
     */
    public void afterSell(Float money);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

需要一个实现类来实现这两个方法

/**
 * 一个生产者
 */
public class Producer implements IProducer {
    /**
     * 销售
     *
     * @param money
     */
    public void sellProduct(Float money) {
        System.out.println("销售了产品,并且拿到了" + money + "钱");
    }

    /**
     * 售后
     *
     * @param money
     */
    public void afterSell(Float money) {
        System.out.println("提供了售后服务,并且拿到了" + money + "钱");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

写一个测试类,当生产商卖出一台电脑,会有百分之 20 的收入进入到经销商的手中,所以我们定一个增强的方法,这个代理方式是基于接口来实现的。只要是接口中的方法执行都会经过这个代理方法中

/**
 * 模拟一个消费者
 */
public class Client {
    @Test
    public void buy() {
        final Producer producer = new Producer();
        //producer.sellProduct(5000f);
        /*
            动态代理
                优点,字节码随用随创建,随用随加载.
                作用:不修改源码的基础上对方法增强
                分类:基于接口的动态代理
                        涉及的类proxy,
                        提供者:jdk官方
                    如何创建代理对象
                        Proxy中的newInstance(),
                    创建代理对象的要求
                        被代理类至少实现一个接口,如果没有则不能使用.
                    newProxyInstance的参数
                        ClassLoader loader,
                            写被代理类的类加载器,固定写法
                        Class<?>[] interfaces,
                            写被代理类的getInterfaces(),固定写法
                        InvocationHandler h
                            写如何代理,通常情况下就是匿名内部类,但不是必须的
                    基于子类的动态代理

         */
        IProducer iproducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * 被代理对象的任何方法都会进过该方法
             * @param proxy     代理对象的引用
             * @param method    当前执行的方法
             * @param args      方法所需要的参数
             * @return 和被代理对象有相同的返回值
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object object = null;
                //提供增强的代码
                //获取方法执行的参数
                Float money = (Float) args[0];
                //判断当前方法是不是销售
                if ("sellProduct".equals(method.getName())) {
                    object = method.invoke(producer, money * 0.8f);
                }
                return object;
            }
        });
        iproducer.sellProduct(8000f);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 基于子类的动态代理

这个代理方法必须有第三方的 jar 包才可以实现 (cglib)

/**
 * 模拟一个消费者
 */
public class Client {
    @Test
    public void buy() {
        final Producer producer = new Producer();
        //producer.sellProduct(5000f);
        /*
            动态代理
                优点,字节码随用随创建,随用随加载.
                作用:不修改源码的基础上对方法增强
                分类:基于子类的动态代理
                        涉及的类enhancer,
                        提供者:第三方jar
                    如何创建代理对象
                        enhancer中的create(),
                    创建代理对象的要求
                        被代理类不能是final类
                    create的参数
                        Class type,
                            写被代理类的类加载器,固定写法
                        Callback callback
                            用于提供增强的,只不过一般写的都是实现类

         */
        Producer proder = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * 被代理对象的任何方法都会经过该方法
             * @param o             代理对象的引用
             * @param method        当前执行的方法
             * @param objects       方法所需要的参数
             *      以上三个和基于接口代理的invoke()中的三个参数是完全一致的
             * @param methodProxy   当前执行方法的代理对象
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object object = null;
                //提供增强的代码
                //获取方法执行的参数
                Float money = (Float) objects[0];
                //判断当前方法是不是销售
                if ("sellProduct".equals(method.getName())) {
                    object = method.invoke(producer, money * 0.8f);
                }
                return object;
            }
        });
        proder.sellProduct(20000f);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#Spring
上次更新: 2025/04/12, 05:37:39
Spring 的依赖注入(DI)
Spring AOP

← Spring 的依赖注入(DI) Spring AOP→

最近更新
01
Reactor 核心
02-24
02
前置条件
10-30
03
计算机网络
09-13
更多文章>
Theme by Vdoing | Copyright © 2019-2025 powered by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式