代理模式

静态代理模式

1.什么是代理模式:

  • 代理模式是个给一个对象提供一个代理对象,并有代理对象控制对元对象的引用。通俗一点就是代理相当于我们所说的中介。
    一般来说代理模式有三个对象:
  • 抽象对象: 代理角色和真实角色对外提供的公共方法,一般是一个接口
  • 真实角色: 需要实现代理角色的接口,并且有真实角色自己的业务逻辑,以便工代理角色调用。
  • 代理角色: 需要实现抽象角色的接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将同意流程都放到代理角色中处理! 而访问者不去访问真实角色,只用去访问代理角色。
    代码验证:(一个果农,一个批发商,一个是小摊贩)
    定义果农:
/**
* 果农的果园
* 只种了苹果
*/
public interface FruitAppleFactory {
   /**
    * 卖水果
    * @param size 多少
    */
   void wholesaleApple(String size);

}

/**
 * 苹果的果农
 */
public class FruitApple implements FruitAppleFactory {

    @Override
    public void wholesaleApple(String size) {
        System.out.println("售卖了"+size+"斤苹果");
    }
}
/**
 * 批发商
 */
public class MiddleAppleShop implements FruitAppleFactory {

    /**
     *我从买苹果的果农手里批发苹果
     */
    FruitAppleFactory fruitApple;

    public MiddleAppleShop(FruitAppleFactory fruitApple) {
        this.fruitApple = fruitApple;
    }

    private void doAfter(){
        System.out.println("精品包装了一下");
    }

    private void doBefore(){
        System.out.println("市区免费送货上门");
    }
    @Override
    public void wholesaleApple(String size) {
        doAfter();
        fruitApple.wholesaleApple(size);
        doBefore();
    }
}

最后一个小摊贩:

        //这是苹果
        FruitAppleFactory apple = new FruitApple();
        MiddleAppleShop middleShop = new MiddleAppleShop(apple);
        middleShop.wholesaleApple("100");

输出结果:

精品包装了一下
售卖了100斤苹果
市区免费送货上门
-------------------------

以上是静态代理模式的实现,静态代理模式的实现很简单,但是一对一的时候会出现静态代理对象数量过多,代码量大,从而导致复杂,可维护性差。比如我要在增加一个香蕉的,橘子的。。。等等。这样一对多的时候就出现了扩展性差的问题。
那么有没有其他方式能够解决呢?----动态代理模式就能来帮助我们了!可以在使用时创建代理类和实例
动态代理模式的优缺点我们先来看一下;
优点:
只需要一个动态代理类就可以解决对个静态代理的问题,避免重复,多余代码。
更强的灵活性。
*缺点:
动态代码的效率要略微第一点,毕竟我们在实现的时候用到了反射。相比静态直接调用对象方法,动态代理则先通过Java 的反射,来简介的调用对象的方法。
应用场景局限,因为Java 的单继承特性。只能针对接口创建代理类,不能针对类创建代理类.

在Java动态代理中有两个重要的类或者接口,一个是InvocationHandler 接口,一个是Proxy 类,这两个类和接口是我们实现动态代理必须的。
InvocationHandler 接口是给动态代理类实现的,负责处理被代理对象的操作的,Proxy 是用来创建动态代理类实例对象的,因为只有得到了这个我们才能调用那些需要代理的方法。
动态代理的就提实现:

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

/**
 * 动态代理类
 */
public class MiddleShopProxy implements InvocationHandler {

    private Object factory;

    public Object getFactory() {
        return factory;
    }

    public void setFactory(Object factory) {
        this.factory = factory;
    }

    public Object getProxyInstance() {
        return Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), this);
    }

    private void doAfter() {
        System.out.println("精品包装了一下");
    }

    private void doBefore() {
        System.out.println("市区免费送货上门");
    }


    /**
     *
     * @param proxy 代理类的实例(对象)
     * @param method 要调用的方法
     * @param args  方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        doAfter();
        Object invoke = method.invoke(factory, args);
        doBefore();

        return invoke;
    }
}

/**
 * 果农
 * 只有香蕉
 */
public interface FruitBananaFactory {

    void wholesaleBanana(String size);
}

/**
 * 香蕉的果农
 */
public class FruitBanana implements FruitBananaFactory {

    @Override
    public void wholesaleBanana(String size) {
        System.out.println("售卖了"+size+"斤香蕉");
    }
}

调用方法

       FruitBananaFactory fruitBananaFactory = new FruitBanana();
        MiddleShopProxy middleShopProxy = new MiddleShopProxy();
        middleShopProxy.setFactory(fruitBananaFactory);


        FruitBananaFactory ban = (FruitBananaFactory) middleShopProxy.getProxyInstance();
        ban.wholesaleBanana("100");

输出结果:

---------动态代理模式---------------
精品包装了一下
售卖了100斤香蕉
市区免费送货上门

简单分析一下代理模式的实现方式:
断点调试一下:

代理类

通过调试发现动态代理中,代理类的类名是$Proxy0 这样的。这个名字为何是这样的呢?,通过查看Proxy.newProxyInstance 方法,可以知道和创建对象有关的代码主要有:

Proxy 创建对象实例

关键点就是getProxyClass0(loader,intfs); 这一句,如何获取代理类的对象?
我们点进去看具体的实现:

 /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

通过proxyClassCache 我们知道Jdk 使用了某种缓存机制缓存了我们 代理类的Class对象,同时get 方法接收的是被代理类的类加载器和类实现的接口。
同时我们在进入这个get 方法,

get 方法

进入这个apply 方法:
apply

可以看到有个ProxyClassFactory 工厂类 ,我们进入这个类中,寻找关键代码:

image.png

String proxyName = proxyPkg + proxyClassNamePrefix + num; 这句代码最后生成了代理类的名称也就是前面所说的$Proxy0 ,至此可以明白代理类是如何生成的了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容