动态代理详解

目录

一、动态代理_代理模式简介

二、动态代理_JDK动态代理 dynamic

三、动态代理_CGLib动态代理

四、JDK和CGLib动态代理的区别


一、动态代理_代理模式简介

        代理模式是23种设计模式之一。设计模式是前人总结的,在软件开发过程遇到常用问题的解决方案,常见的设计模式有单例模式、工厂模式、适配器模式等等。

        代理模式的作用是在不修改原对象的基础上增强该对象的方法。比如官方购买苹果手机不赠送充电头,此时京东平台作为苹果的代理商,可以在代理销售苹果手机时赠送充电头

        代理模式分为静态代理、动态代理。静态代理会生成一个代理类,动态代理不会生成代理类,直接生成代理对象。

二、动态代理_JDK动态代理 dynamic

        JDK动态代理是针对接口进行代理,所以我们要写被代理的接口和该接口的实现类。

// 被代理接口

package com.example.dynamic;

public interface Apple {

    // 卖产品
    String sell(double price);

    // 维修
    void repair();
}

// 被代理接口的实现类

package com.example.dynamic;

public class AppleImpl implements Apple{

    @Override
    public String sell(double price) {
        System.out.println("产品卖了" + price + "元");
        return "ipone14";
    }

    @Override
    public void repair() {
        System.out.println("苹果售后维修");
    }
    
}

// 代理方式类,定义被代理方法的增强方式

// 该类实现InvocationHandler接口,重写invoke方法,定义方法的增强方式

package com.example.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

// 代理方式类,定义被代理方法的增强方式
// 该类实现InvocationHandler接口,重写invoke方法,定义方法的增强方式
public class ShoppingProxy implements InvocationHandler{

    // 被代理对象
    private Apple apple;

    public ShoppingProxy(Apple apple){
        this.apple = apple;
    }

    /**
     * 定义原方法的增强方式
     * @param proxy 被代理对象
     * @param method 被代理对象
     * @param args 被代理对象调用的方法时,传入的参数
     * @return 方法的返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 被代理对象执行的方法名
        String name = method.getName();
        if("sell".equals(name)){
            // 增强参数
            double price = (double) args[0]*0.9;
            // 执行方法
            Object result = method.invoke(apple, price);
            // 增强返回值
            return result + "和充电头";
        }
        else if("repair".equals(name)){
            // 增强方法流程
            System.out.println("专属客服为你服务!");
            return method.invoke(apple, args);
        }
        else{
            // 什么都不增强
            return method.invoke(name, args);
        }
    }
}

接下来测试一下:

package com.example.dynamic;

import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        // 被代理对象
        Apple apple = new AppleImpl();
        // 代理方式对象
        ShoppingProxy shoppingProxy = new ShoppingProxy(apple);
        // 生成代理对象
        Apple appleJD = (Apple) Proxy.newProxyInstance(
            apple.getClass().getClassLoader(), // 类加载器
            apple.getClass().getInterfaces(), // 被代理接口
            shoppingProxy  // 代理方式对象
        );

        // 执行未增强的方法
        System.out.println("执行未增强的方法");
        String sell = apple.sell(6000);
        System.out.println(sell);
        apple.repair();

        System.out.println("--------------------------");

        // 执行增强后的方法
        System.out.println("执行增强后的方法");
        String sellProxy = appleJD.sell(6000);
        System.out.println(sellProxy);
        appleJD.repair();
    }
}

运行结果:

ok 啊,确实实现了动态代理模式,但是这个时基于JDK的动态代理模式,还是需要我们自己去写接口,接下来介绍一种基于CGLib的动态代理模式 

三、动态代理_CGLib动态代理

        CGLib动态代理简化了JDK动态代理的写法,JDK是针对接口代理,而CGLib是针对类代理。

我们得在pom.xml文件引进cglib的依赖,所以我们现在pom.xml加上以下代码

<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.3.0</version>
</dependency>

// 被代理类

package com.example.dynamic_cglib;

public class Apple {

    // 卖产品
    public String sell(double price){
        System.out.println("产品卖了"+price+"元");
        return "ipone13";
    }

    // 维修
    public void repair(){
        System.out.println("苹果售后维修");
    }
}

// 代理方式类,实现MethodInterceptor接口,重写intercept方法

package com.example.dynamic_cglib;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;


public class ShoppingProxy implements MethodInterceptor{

    // 被代理对象
    private Apple apple;

    public ShoppingProxy(Apple apple){
        this.apple = apple;
    }

    /**
     * 定义原方法的增强方式
     * @param o 被代理对象
     * @param method 被代理对象调用的方法
     * @param args 被代理对象调用的方法时,传入的参数
     * @param methodProxy 底层生成的代理类的引用
     * @return 方法的返回值
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        String name = method.getName();
        if("sell".equals(name)){
            double price = (double) args[0]*0.8;
            Object result = method.invoke(apple, price);
            return result+"数据线";
        }
        else if("repair".equals(name)){
            System.out.println("专属客服为你服务!");
            return method.invoke(apple, args);
        }
        else{
            return method.invoke(apple, args);
        }
    }
}

ok ,再让我们写一个测试类,看看能否好使,注意这里生成代理对象就不是用JDK那个方法了

package com.example.dynamic_cglib;

import org.springframework.cglib.proxy.Enhancer;


public class Test {
    public static void main(String[] args) {
        // 被代理对象
        Apple apple = new Apple();
        // 代理方式
        ShoppingProxy shoppingProxy = new ShoppingProxy(apple);
        // 生成代理对象
        Apple appleTB = (Apple) Enhancer.create(Apple.class,shoppingProxy);

        // 执行未增强的方法
        System.out.println("执行未增强的方法");
        String sell = apple.sell(9000);
        System.out.println(sell);
        apple.repair();

        System.out.println("-------------------");

        // 执行增强后的方法
        String sellProxy = appleTB.sell(9000);
        System.out.println(sellProxy);
        appleTB.repair();
    }
    
}

ok,看一下运行结果,也确实进行了动态代理。

四、JDK和CGLib动态代理的区别

         所以,通过上述两个例子我们可以知道关于JDK动态代理和CGLib动态代理的区别就是JDK是基于接口的,而CGLib是基于类的。

        所以,你学hui了吗?

评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会洗碗的CV工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值