浅谈java 动态代理/为什么使用动态代理

本文详细解析了代理模式的概念及其应用场景,对比静态代理与动态代理的区别,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要想明白动态代理,先理解一下什么是代理,怎样"静态代理":
基于反射实现

代理: 代购,中介,换ip,商家 …
留学中介(代码) :帮助美国学校招生,中介是学校的代理,中介代替学校完成招生功能
代理的特点:
1.中介和代理他们做的事情一致
2.中介是学校的代理,学校是目标
3.中介是代理,不能白干活,需要收取费用
4.代理不让你访问到目标

为什么使用代理:
1.中介是专业的,方便
2.家长现在不能自己访问学校,家长没有能力访问学校,或者美国学校不接受个人来访

类似于:
买家–(买东西)—>商家—(代理)—>厂家
卖东西都是商家卖,商家是某个商品的代理,个人卖东西,不会接触到厂家

在开发中的使用: a类调用c类的方法,完成某个功能,但是c不让a调用,a不能调用c的方法
解决:
在a和c之间创建一个b代理 使c让b访问
a—访问—>b—访问—>c

实际案例:登录,注册验证码,验证码是手机短信
发短信项目—访问—>移动子公司/关联公司----访问—>中国移动
代理模式:
代理模式是指,为其他对象提供一种代理以控制这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介作用

使用代理模式的作用:
1.功能增强:在原有的功能上,增加了额外的功能,新增加的功能叫做功能增强
2.访问控制:代理类不让访问目标,例如商家不让用户直接访问厂家

实现代理的方式:
1.静态代理:
1)代理类是自己手工实现的,自己创建一个java类,表示代理类
2)同时你所要代理的目标类是确定的
特点: 1)实现简单 2)理解容易

实现:
用户:客户端类
商家:代理,代理某个U盘品牌
厂家:目标类
三者关系:用户(客户端)----商家(代理)----厂家(目标)
商家和厂家都是卖u盘的,他们完成的功能一致:卖U盘
实现步骤:
1.创建一个接口,实现卖U盘方法,表示厂家和商家做的事情
2.创建厂家类,实现1中的接口
3.创建商家,就是代理,也需要实现1中的接口
4.创建客户端类,调用商家的方法买一个U盘
静态代理的实现

静态代理优点:1.实现简单 2.容易理解
静态代理的缺点:(当目标类和代理类很多的时候)
1.当目标类增加了,代理类可能需要成倍增加 (代理类数量过多)
2.当接口中功能增加了,或者修改了,会影响众多的实现类,厂家类,代理类会影响比较多
示例代码:

//表示功能,厂家,商家都要完成的功能
public interface UsbSell {
    //定义方法 参数 amount:表示一次购买的数量
    //返回值表示一个u盘的价格
    float sell(int amount);
    //可以写多个别的方法
}

代表一个制造U盘的厂家sx

//目标类:三星厂家,不接受用户的单独购买
public class UsbSamaungFactory implements UsbSell {
        /*
        一个128G盘价格160元
        后期根据amount,实现不同的价格
        根据数量不同,返回的价格不同
         */
    @Override
    public float sell(int amount) {
        if(amount>=3&&amount<5){
            System.out.println("厂家发货价格为150");
            return 150.0f*amount;
        }else if (amount>=5&&amount<10){
            System.out.println("厂家发货价格为145");
            return 145.0f*amount;
        }else if(amount>=10&&amount<30){
            System.out.println("厂家发货价格为140");
            return 140.0f*amount;
        }else if(amount>=30&&amount<50){
            System.out.println("厂家发货价格为138");
            return 138.0f*amount;
        }else if (amount>=50&&amount<100){
            System.out.println("厂家发货价格为135");
            return 135.0f*amount;
        }else if(amount>=100){
            System.out.println("厂家发货价格为130");
            return 130.0f;
        }
        System.out.println("厂家发货价格为160");
            return 160.0f*amount;
    }
}

模拟代理:pdd

public class Pdd implements UsbSell {
    private UsbSell facotory=new UsbSamaungFactory();
    @Override
    public float sell(int amount) {
        //向厂家发送订单,告诉厂家,买了u盘,厂家发货
        float price = facotory.sell(amount);
        //亲民dd
        System.out.println("pdd出售的单价为"+(price+5));
        price=(price+5)*amount;
        //返回增加后的价格
        return price;
    }
}

模拟用户购买U盘

public class shopMan {
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        System.out.println("请输入您要购买的数量:");
        int count = s.nextInt();
        //创建pdd代理的对象
        Pdd pdd=new Pdd();
        System.out.println("pdd向你的亲朋好友们砍了一刀");
        float ddprice = pdd.sell(count);
        System.out.println("通过pdd销售"+count+"个三星u盘总价格为"+ddprice);
    }
}

针对静态代理的缺点使用动态代理解决:
在静态代理中目标类很多的时候,可以使用动态代理,避免静态代理的缺点
动态代理中目标类即使很多(很多U盘厂家):
1.代理类数量可以很少
2.当你修改了接口的方法时,不影响代理类(不影响淘宝/pdd)
动态代理:
在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理的目标类
不用写淘宝/pdd的java文件,jdk使用反射机制创建代理类淘宝/pdd对象,并且动态的获取代理的目标类三星/金士顿…
(商家PDD中new的厂家是动态的,可以是三星也可以是pdd),也就是说动态代理是一种创建java对象的能力,让你不用创建TaoBao类
动态代理就是使用jdk的反射机制创建对象的能力,创建的是代理类的对象,而不是创建的类文件,不用写java文件.
动态:执行时,调用jdk提供的方法才能创建类的对象

动态代理的两种实现方式:
1.JDK动态代理(理解):使用java反射包中的类和接口实现动态代理的功能
反射包 java.lang.reflect 里面有三个类;InvocationHandler,Method,
proxy.
2.CGLIB动态代理(了解):cglib通过继承目标类,创建它的子类,在子类中重写父类的同名方法,实现功能的修改.因为cglib是继承,重写方法,所以要求目标类不能是final的,方法也不能是final的.oglib的要求目标类比较宽松,只要能继承就可以,oglib在很多框架中使用,如mybatis,spring框架中都有使用

1.基于反射:Method 类,表示类中的方法,通过Method可以执行某个方法
2.jdk动态代理的实现:
反射包: java.lang .reflect 里面有三个类: InvocationHandler,Method,Proxy

一:InvocationHandler
invoke():表示代理对象要执行的功能代码,你的代理类要完成的功能就写在invoke()方法中
代理类完成的功能:
1.调用目标方法,执行目标方法中的功能
2.功能增强,在目标方法调用时,增加功能
方法原型:
public Object invoke(Object proxy,Method method,Object[] args)
参数:Object proxy : jdk创建的代理对象,无需赋值
Method method:目标类中的方法,jdk提供method对象的
Object[] args:目标类中方法的参数,jdk提供的
InvocationHandler 接口:表示你的代理要干什么
使用: 1.创建类实现接口InvocationHandler
2.重写invoke()方法,把原来静态代理中的代理类要完成的功能写在invike中

二:Method类:表示方法的,确切的说就是目标类中的方法
作用:通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)
通过method.invoke() 可以执行任意对象的方法,而不需要知道方法的名称,因为method执行的方法是jdk帮你确定的,不需要管理
method.invoke()就是用来执行目标方法的,等同于静态代理中的:
//向厂家发送订单,告诉厂家,买了u盘,厂家发货
float price = facotory.sell(amount);

三:Proxy类:核心类,创建代理对象,之前创建对象都是new类的构造方法() 现在我们是使用Proxy类的方法,代替new的使用
方法: newProxyInstance()
作用:创建代理对象,等同于静态代理中的TaoBao taobao=new TaoBao();
方法原型:
public static Object newProxyInstance(ClassLocader loader,
Class<?>[] interfance,
InvocationHandler h)

参数:
1,classLoader loader 类加载器,负责向内存中加载对象的,使用反射获取对象的ClassLoader
例: 类a a.getClass().getClassLoader() 目标对象的类加载器
2.Class<?>[] interfance:接口,目标对象实现的接口,也是反射获取的
3.InocationHandler h:我们自己写的,代理类要完成的功能
Proxy是代理对象,

实现动态代理的步骤
1.创建接口,定义目标类要完成的功能
2.创建目标类实现接口
3.创建InvocatiionHandler接口的实现类,在invoke方法中完成代理类的功能:
1.调用目标方法
2.增强功能
代码实例:还是上例的接口和厂家(换个变量名),所以没有列出

public class PddShellHandler implements InvocationHandler {
    private Object target=null;

    public PddShellHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object res=null;
        res=method.invoke(target,args);
        if(res!=null){
            Float pries=(float)res;
            pries=pries+5;
            res=pries;
        }
        System.out.println("     pdd给你的亲戚朋友们一人砍了一刀");
        return res;
    }
}

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class MainShop {
    public static void main(String[] args) {
        //使用Proxy创建代理对象
        /*
        public static Object newProxyInstance(ClassLocader loader,
                                            Class<?>[] interfance,
                                            InvocationHandler h)
         */
        //创建一个目标对象(给谁创建代理)
        UsbShell factory=new UsbKingFactory();
        //创建InvocationHandler对象
        InvocationHandler handler=new UsbShellHandler(factory);
        //创建代理对象
        UsbShell proxy= (UsbShell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(),
                handler);
        float price = proxy.sell(100 );
        System.out.println("通过动态代理对象  调用方法:"+price);
    }
}

动态代理的执行原理:
在这里插入图片描述

在开发中的作用:
你所在的项目中有一部分功能是其他部门已经开发好的,可以使用,但是这个功能还有缺点,不能满足自己的项目需要自己增加代码,而不去修改原来的文件

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值