栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java静态代理和动态代理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java静态代理和动态代理

代理模式

什么是代理模式:

例如,有A B C三个类,A原来可以调用C类的方法,现在因为某种原因C类不允许A类调用其方法,但B类可以调用C类的方法,A类通过B类调用C类的方法。这里B是C的代理,A通过代理访问C。

现实生活中也有各种代理模式相关的例子:比如一个公司老板(目标类),普通人(客户类)想找他签文件,一般是不能直接找到老板的,而是通过去找老板的经纪人(代理类),让经纪人帮忙找老板签文件。又比如,平时租房子,我们(客户类)一般都是无法直接找到房东(目标类)租房的,房东会把房子代理给中介(代理类),中介负责帮房东把房子租出去。如果我们想要租房,就会去找中介,然后中介再去和房东确认。

作用

1、功能增强:在原有的功能上,增加了额外的功能

2、控制访问:目标类不让访问其他类访问,只让代理类访问

静态代理

优点:实现简单,容易理解

缺点:

1、当目标类增加了,代理类也要增加

2、当接口中的功能增加或修改,会影响众多的实现类,代理类,他们都需要同步修改

假设小明想买一件耐克球衣,他可以在淘宝店铺上进行购买,然后淘宝店铺又会去耐克工厂拿货,拿货价是100元一件,因为淘宝商家也要赚钱,所以加价了50,所以小明买下一件球衣的价格是150。这个例子中淘宝商家就是代理。

下面用静态代理实现这个例子:

1、定义一个卖衣服的接口

 
public interface SellClothes {
    float sell(int count);
}

2、定义一个目标类,实现卖衣服的这个接口,这里的目标类就是耐克工厂,在这里卖一件衣服的价格是100元

public class NikeFactory implements SellClothes {
    @Override
    public float sell(int count) {
        System.out.print("目标类,执行sell目标方法。价格是:" + 100f * count);
        return 100f * count;
    }
}

3、定义一个代理类,实现买衣服这个接口,这里的代理类就是淘宝店铺,店铺这里卖一件衣服是150元

public class TaoBaoShop implements SellClothes {
    //持有目标类对象(跟耐克工厂有合作)
    SellClothes nikeFactory = new NikeFactory();

    @Override
    public float sell(int count) {
        //去耐克工厂拿货
        float price = nikeFactory.sell(count);
        //在拿货价的基础上每件衣服加价了50元,再卖出去
        System.out.print("代理类,执行sell目标方法,并对价格进行加价。最终价格是:" + (float) (price * (1.5)));
        return (float) (price * (1.5));
    }
}

4、创建代理对象,执行目标方法

public static void main(String[] args) {
    SellClothes taoBaoShop = new TaoBaoShop();
    taoBaoShop.sell(10);
}

5、输出结果如下:

动态代理

在静态代理中,目标类很多的时候,可以使用动态代理,避免静态代理的缺点。

动态代理中目标类即使很多,代理类数量可以很少,当你修改了接口中的方法时,不会影响代理类

在程序执的过程中,使用jdk反射机制,创建代理对象,并动态的指定要代理的目标类。

不需要定义代理类的.java文件——其实就是jvm运行时,动态创建class字节码并加载到jvm中

动态代理有两种实现方式:

1、jdk动态代理

缺点:要求目标类必须有接口,如果没有,则无法使用该方式。

假设小明想买一件耐克球衣,他可以在淘宝店铺上进行购买,然后淘宝店铺又会去耐克工厂拿货,拿货价是100元一件,因为淘宝商家也要赚钱,所以加价了50,所以小明买下一件球衣的价格是150。这个例子中淘宝商家就是代理。

下面用jdk动态代理实现这个例子:

1、定义一个卖衣服的接口

 
public interface SellClothes {
    float sell(int count);
}

2、定义一个目标类,实现卖衣服的这个接口,这里的目标类就是耐克工厂,在这里卖一件衣服的价格是100元

public class NikeFactory implements SellClothes {
    @Override
    public float sell(int count) {
        System.out.print("目标类,执行sell目标方法。价格是:" + 100f * count);
        return 100f * count;
    }
}

3、创建一个InvocationHandler,完成代理对象的功能——去耐克工厂拿货,并加价50元

public class MySellHandler implements InvocationHandler {

    private Object target = null;

     
    public MySellHandler(Object o) {
        target = o;
    }

    
    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        //目标方法的返回值
        Object res = null;
        //执行目标方法,传参:target:目标类实例,args:目标方法所需参数
        res = method.invoke(target, args);
        //执行一些额外的操作,这里是对原价格进行加价
        if (res != null) {
            Float price = (Float) res;
            res = price + 50f;
        }
        System.out.print("代理类,执行sell目标方法,并对价格进行加价。最终价格是:" + res);
        return res;
    }
}

4、使用Proxy类的静态方法,创建代理对象。并把返回值转为接口类型。

public static void main(String[] args) {
        //1、创建目标类对象——耐克工厂
        SellClothes nikeFactory = new NikeFactory();
        //2、创建InvocationHandler对象
        InvocationHandler handler = new MySellHandler(nikeFactory);
        //3、创建代理对象(淘宝代理)
        SellClothes taoBaoProxy = (SellClothes) Proxy.newProxyInstance(
                //目标类的类加载器
                nikeFactory.getClass().getClassLoader(),
                //目标类实现的接口
                nikeFactory.getClass().getInterfaces(),
                //InvocationHandler对象
                handler
        );
        //淘宝代理对象执行sell方法
        taoBaoProxy.sell(1);
    }

5、输出结果如下:

2、CGLIB动态代理

不要求目标类有接口,其原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。(继承目标类,创建它的子类,在子类中重写父类的同名方法,实现功能的修改)

缺点:要求目标类和里面的方法都不能是final修饰的

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/344829.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号