源码基础 -- 动态代理(1)

对于Spring和MyBatis这两个框架我们基本都用过。也在网上了解到Spring的AOP和MyBatis的Mapper的原理就是java的动态代理机制,今天我们就来了解下JDK的动态代理。

基础知识

1.什么是代理

代理,也叫代理模式,是常用设计模式的一种。
官方定义:对其他对象提供一种代理从而控制对这个对象的访问。就是,代理类 代理 被代理类,来执行被代理类里的方法。
个人理解:代理就是委托的意思,本来一件事你自己可以做,但是你不想做,或是现在没时间做,你委托给别人,找个人来帮你做。

2.JDK动态代理和CGLIB代理

区别:JDK动态代理只能对实现了接口的类生成代理,而不能针对类,CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承),从这里可以看出,CGLIB不能对申明为final的类,或是final方法实行代理。
场景:Spring中的Bean实现接口时,使用的是JDK的动态代理,当Bean没有实现接口时,使用CGlib代理。
效率:CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK1.6以前要比使用JDK动态代理效率高。但是JDK1.7以后逐步对JDK动态代理进行了优化,效率要高于CGLIB代理。

JDK动态代理实现

//1.先定义一个代理接口
public interface SayHello {
    void sayHello(String name);
}
//2.定义一个类,实现上述接口,并实现其方法
public class SayHelloImpl implements SayHello {
    @Override
    public void sayHello(String name) {
        System.out.println("hello : " + name);
    }
}
//使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类
//3.定义一个代理处理类,需要实现InvocationHandler接口
public class SayHelloInvocationHandler implements InvocationHandler {
    private  Object target;
    public SayHelloInvocationHandler(Object target){
        this.target = target;
    }
    //运行代理类中的方法时,实际上都会执行这个方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(target, args);
    }
}
//4.测试
public class ProxyTest {
    public static void main(String[] args) {
        //中介类
        SayHelloInvocationHandler handler = new SayHelloInvocationHandler(new SayHelloImpl());
        //生成代理对象
        SayHello sayHello = (SayHello)Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class[]{SayHello.class}, handler);
        sayHello.sayHello("zhangsan");
    }
}

实现起来很简单,但有没有考虑过一个问题,本来就有了实现类,直接调用实现类就好了,为什么要用代理。也有人会拿现实中的例子来举例,张三要取快递,但是他现在很忙就委托李四帮忙取。别闹了,java中的对象有忙的时候吗,不行咱就再new一个出来。

动态代理是用来干嘛的呢?

我的理解有两层含义。一:在原有功能不变的基础上,给需要代理的方法增加统一功能,如增加日志处理(如spring的AOP),数据采集等。二:动态生成接口的实现类(如MyBatis的Mapper代理)

一、增加功能

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("do before.");
        method.invoke(target, args);
        System.out.println("do end.");
        return null;
    }

这样给被代理类的所有方法都增加了新的功能。也可加一些判断逻辑只给指定方法增加新功能。

二、生成接口实现类

//在需要代理的接口出现前(即先有该方法,后有代理接口)该方法的逻辑已经定型,可通过反射获取methon的信息,返回值,方法名方法参数等,当然方法体是需要在这里实现的。或是获取接口的信息,可通过构造方法传入接口的类类型。
    public Object sayHello(Method method, Object[] args){
        System.out.println("hello:"+method.getName() + "..." + args[0]);
        return null;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        sayHello(method,args);//在这里调用代理实现方法
        return null;
    }

注意,这种情况不能直接执行 method.invoke(target, args);此时该方法只是接口中的方法,并没有方法的实现。需要执行特定逻辑,如这里的sayHello方法,方法的信息(方法名,返回值,参数,注释等)都可以通过method获取。这种方式代理的方法一般都有特定的统一逻辑,他会限定你使用特定的注解,或是使用指定规则的方法名,他会预先根据设定的这些规则生成方法的实现逻辑,如MyBatis的Mapper,需要使用规则的方法名,或是指定注解。其功能都是固定的对数据的增删改查等,通过注解或方法名来判断具体的增删改查,但这些逻辑在需要代理的接口定义前就已经确定了。
当然获取class和method的原信息需要使用java的反射机制,然后再根据这些原数据信息,实现对应的逻辑,达到动态实现类和方法的目的。

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,826评论 18 139
  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 12,311评论 6 86
  • 文/白若狐 接连两日,因为儿子莫名的生病,我整日整夜的无法安眠,更不敢有丝毫的松懈。我像一只时刻保持警惕的小兽一样...
    白若姝阅读 1,970评论 5 26
  • 最近朋友圈,微博被一群名为“佛系少年”的人刷爆了,可能有的人还不理解,佛系少年是什么鬼?是出了家的少年吗?那么现在...
    小圆圈圈ooo阅读 12,154评论 4 1
  • 我与iPhone 嘿,小四,你好吗! 嘿!你好! 什么事这么开心? 啊?我有开心吗? 没有吗?感觉搭话时的语气很轻...
    宁如尘FlowEr阅读 258评论 0 0