普通代理模式与动态代理

代理模式如同字面意思自己做不了的事交给别人代理,代理无论是在生活中还是在编码中都会常常遇见,比如最近比较火的微商,厂商给供货给微商,微商代理厂商卖商品。这个就是代理,那么它在编程中有什么作用呢?
说的通俗一点就是为其他对象提供一种代理以控制对这个对象的访问。主要解决的问题是:在直接访问对象时带来的问题,比如说,要访问的对象在远程的机器上。
举例说明
为了更好的理解代理模式,我为大家举个追女孩的案例。
//我先定义一个男孩的类

public interface Boy {
    //定义一个追的方法。
    void zhui(String name);
}

//定义一个不害羞人的类代理害羞人做表白的事。

public class BuHaiXiu implements  Boy {

    Boy beiWoBangMang = null;

    public void setBeiWoBangMang(Boy beiWoBangMang) {
        this.beiWoBangMang = beiWoBangMang;
    }

    @Override
    public void zhui(String name) {
        if("nvsheng".equals(name)){
            System.out.println("我自己亲自追求");
        }else{
            beiWoBangMang.zhui(name);
        }


    }
}

//害羞人的类

public class HaiXiu implements Boy{
    @Override
    public void zhui(String name) {
        System.out.println("我想追求" + name);
        System.out.println("我的套路......");
    }
}

大家在上面的代码中很容易就可以看出不害羞的人这个类是代理类,害羞的人每次表白都会被代理类拦截,当害羞的人追求的目标是女神时,代理的那个不害羞的人就不再帮害羞的人,而是自己追求。所以在代理模式中可以做到访问权限的控制。

动态代理模式

1.什么是动态代理:
代理类在运行时创建的代理方式称为动态代理。动态代理与静态代理最大的不同是动态代理的代理类不是在java代码中定义的,而是在运行时根据我们的java代码 “指示”动态生成的。这样的不同给动态代理带来的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
2.那么动态代理是如何实现的呢?
要了解动态代理的实现首先要了解java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口。首先我们先来理解下Proxy这个类,这个类的作用主要是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法
比如:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

这个方法的作用就是得到一个动态的代理对象,接收三个参数,那么这三个参数,代表的是什么呢?
第一个参数:用来加载动态生成的代理类,定义了由哪个ClassLoader对象,并对动态生成的代理类进行加载。
第二个参数:被代理类实现的接口,以便 Proxy 这个工具类要知道哪些方法可以被代理,此参数是个数组。
第三个参数:就是被代理的所有方法都转到 InvocationHandler 的 Invoke 方法去执行。

InvocationHandler接口
介绍完proxy这个方法,接下来我们来了解下InvocationHandler这个接口,每个动态代理类都必须实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由这个接口的(唯一的方法) invoke 方法来进行调用。那么invoke方法是由什么组成的呢?

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

由此可以看出invoke方法由三个参数组成,这三个方法所代表的含义是:
第一个参数:proxy 就是动态生成的代理类的对象
第二个参数:method 被代理类的当前被调用的方法
第三个参数:args 被代理类的当前被调用的方法的参数数据

介绍完proxy类和InvocationHandler接口后,接下来就举个例子,具体说明下吧。

//首先定义一个MyInfo接口里面有两个方法。
public interface MyInf {
    void insert(String s);
    void update();
}
//注解我这里为了减少代码的边幅,把数据库的连接写成了输出
public class MyInfImpl implements MyInf {
    @Override
    public void insert() {
        System.out.println("insert in myinfimpl");
    }

    @Override
    public void update() {
        System.out.println("update in myinfimpl");
    }
}
public class MyInvocationHandler implements InvocationHandler {
    private MyInf myInf;
     //set方法,给我们要代理的真实对象赋初值
    public void setMyInf(MyInf myInf) {
        this.myInf = myInf;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----before-----");
      //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        Object result= method.invoke(myInf,args);
        System.out.println("----after-----");
        return result;
    }

最后测试类

public class Main {
    public static void main(String[] args) {

        MyInf myInf = new MyInfImpl();
       
        InvocationHandler invocationHandler = new MyInvocationHandler();
        ((MyInvocationHandler) invocationHandler).setMyInf(myInf);
       
       MyInf proxy = (MyInf) Proxy.newProxyInstance(myInf.getClass().getClassLoader(),
                myInf.getClass().getInterfaces() ,invocationHandler );

       if(proxy!=null) {
      
           proxy.insert();
       }
    }
}

结果

----before-----
insert in myinfimpl
----after-----

就这样一个简单的动态代理就完成了。还有注意的一细节:
Proxy 这种动态代理机制,有一个前提:被代理类有实现接口,如果没有, Proxy 工具类就无效
其次为什么这行代码要转类型呢?

MyInf proxy = (MyInf) Proxy.newProxyInstance(myInf.getClass().getClassLoader(),
                myInf.getClass().getInterfaces() ,invocationHandler );

原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是MyInf类型,所以就可以将其转化为MyInf类型了。

另外想了解jdbc中的动态代理的朋友可以加qq:1402485086我们一起探讨下。

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