mybatis静态代理jdk动态代理
背景有时目标对象不可直接访问,只能通过代理对象访问 图示:
示例1:房东 ===> 目标对象房屋中介 ===> 代理对象你,我 ===> 客户端对象 示例2:运营商(电信,移动,联通) ===> 目标对象第三方公司 ===> 代理对象开发的应用程序需要发送短信的功能(或者需要支付功能) ===> 客户端对象 代理模式的作用控制客户对目标对象的访问 增强访问功能 代理模式的分类静态代理 动态代理JDK动态代理CGLib动态代理 静态代理特点目标对象和代理对象实现同一个业务接口 目标对象必须实现接口 代理对象在程序运行前就已经存在 静态代理示例与原理分析业务背景
分析定义业务接口:面向接口编程,定义业务 目标对象实现接口:业务的核心功能到底怎么实现 代理对象(扩展业务 + 核心业务)实现了目标对象所实现的接口,说明代理对象有资历进行代理对核心业务进行扩展调用目标对象实现核心业务(只能目标对象自己完成) 客户:无法直接访问目标对象,要访问代理对象 代码实现面向接口编程 成员变量是接口类型 传入目标对象,方法的参数设计为接口 调用时,接口指向实现类 静态代理对象代码 package com.example.service.impl; import com.example.service.Service; public class Agent implements Service { //定义接口对象 public Service target; public Agent (){} //传入接口对象 public Agent (Service target){ this .target = target; } @Override public void sing () { System.out.println( "协商演出时间......" ); System.out.println( "协商演出地点......" ); //目标对象完成核心业务,接口指向实现类,调用实现类的方法 target.sing(); System.out.println( "协商演出费用......" ); } } 静态代理优缺点优点:能够灵活地进行目标对象的切换适用于业务固定,目标对象可灵活切换的场景 缺点:无法进行功能的灵活处理,当业务发生改变时,所有涉及到的实现类代码和代理对象代码都要改变 动态代理JDK动态代理特点目标对象必须实现业务接口 JDK代理对象不需要实现业务接口 JDK代理对象在程序运行前不存在,程序运行时动态的在内存中构建(根据受代理的对象动态创建) JDK动态代理可以灵活的进行业务功能的切换 JDK动态代理用到的类和接口使用现有的工具类完成JDK动态代理 先了解两个单词的意思InvocationHandler:调用处理程序invoke:调用 Method类反射时用的类,用来进行目标对象的目标方法的反射调用 method对象,接住我们正在调用的方法 sing(),show()method == sing(),show(),即:待调用的方法method.invoke() ==> 相当于手工调用目标方法 sing(),show(); InvocationHandler接口用来实现代理和业务功能,我们在调用时使用匿名内部实现匿名内部实现:new接口的同时,重写接口中的方法(相当于定义了该接口的一个实现类) Proxy类位于:java.lang.reflect.Proxy包下 有一个核心方法:Proxy.newProxyInstance(....),专门获取动态代理对象,有三个参数 参数1:ClassLoader loader 目标对象的类加载器 目的:获取类方法等信息,毕竟底层还是要调用受代理对象所实现的方法 传入:targetObj.getClass().getClassLoader(); 参数2:Class<?>[] interfaces 目标对象实现的所有接口,类的接口可以有多个 目的:获取目标对象实现的所有接口以及接口的相关信息,毕竟底层要知道目标对象都可以完成哪些业务操作 传入:targetObj.getClass().getInterfaces(); 上面两个参数为代理对象动态的创建和调用目标对象的方法提供了数据支持,第3个参数相当于调用程序 参数3:InvocationHandler 实现代理功能的接口,这里代理功能包括:扩展的功能 + 核心业务功能,传入的匿名内部实现如下 new InvocationHandler() { @Override public Object invoke( Object obj, //用来反射调用方法 Method method, //待调用方法需要的参数 Object [] args) throws Throwable { //扩展业务 System.out.println( "协商演出时间......" ); System.out.println( "协商演出地点......" ); //核心业务,具体调用什么方法根据外层业务来反射调用对应方法 Object res = method.invoke(target, args); //扩展业务 System.out.println( "协商演出费用......" ); //目标对象执行的目标方法的返回值 return res; } } JDK动态代理示例代理工厂代码 package com.example.proxy; import com.example.service.Service; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory { //目标对象 Service target; public ProxyFactory(){} public ProxyFactory(Service target){ this .target = target; } //返回代理对象 public Object getAgent(){ return Proxy.newProxyInstance( //需要知道受代理对象的类信息 target.getClass().getClassLoader(), //需要知道受代理对象实现的所有接口信息 target.getClass().getInterfaces(), //反射调用目标对象的目标方法 new InvocationHandler() { @Override public Object invoke( Object obj, //用来反射调用方法 Method method, //待调用方法需要的参数 Object[] args) throws Throwable { //扩展业务 System. out .println( "协商演出时间......" ); System. out .println( "协商演出地点......" ); //核心业务,具体调用什么方法根据外层业务来反射调用对应方法 Object res = method.invoke(target, args); //扩展业务 System. out .println( "协商演出费用......" ); //目标对象执行的目标方法的返回值 return res; } } ); } } 测试代码示例package com.example.proxy; import com.example.service.Service; import com.example.service.impl.SuperStarZhou; import org.junit.Test; public class TestProxyFactory { @Test public void testGetProxy(){ //确定客户需求 ProxyFactory factory = new ProxyFactory( new SuperStarZhou()); //根据需求动态返回对应类型的代理对象 Service agent = (Service) factory .getAgent(); //依托对应类型的动态代理对象完成业务:扩展业务(动态代理对象完成) + 核心业务(目标对象完成) agent.sing(); } @Test public void testGetProxy2(){ ProxyFactory factory = new ProxyFactory( new SuperStarZhou()); Service agent = (Service) factory .getAgent(); String res = ( String ) agent.show( 60 ); System.out.println(res); } } 注意可被代理的方法应该是受代理对象实现的所有接口中的方法与其所有实体方法的交集 本类中独有的方法不被代理 类型的转变 @Test public void testGetProxy2 () { ProxyFactory factory = new ProxyFactory( new SuperStarZhou()); Service agent = (Service) factory.getAgent(); Service liu = new SuperStarLiu(); System. out .println( "类型1: " + liu.getClass()); System. out .println( "类型2: " + agent.getClass()); } /* 输出结果: 类型1: class com.example.service.impl.SuperStarLiu 类型2: class com.sun.proxy.$Proxy7 */
大家发现了没有?现在社会上逐渐出现了一些诡异的现象今天,我们就再来说说现在社会上的一些怪现象,我想当我说出来的时候,大家一定也会颇有感受。第一个现象,就是如果家里面有老人过世亲属自己不哭,反倒花钱雇人来哭。第二点,有些宝妈明明有奶
新生儿灵魂四问?1。新生儿发生黄疸怎么办?在出生后的两三天,半数以上的新生儿会患上黄疸。黄疸虽然并不会造成严重后果,却仍然属于一种疾病。它表明孩子体内已经产生胆红素(当红细胞破裂时体内产生的黄色色
风之子纳什的劲爆情史一2000年,媒体曝出,纳什和好莱坞明星伊丽莎白赫莉约会。那时伊丽莎白赫莉刚刚和男友分手,正是感情的低谷期,再加上伊丽莎白赫莉那双含情脉脉的眼神,众多追求者慕名而来,唯有纳什有缘一
网络,一个可以放飞灵魂的地方文毛六灵与肉,似乎是一个老掉牙的话题了。在过去,由于吃不饱穿不暖,常常使我们的精神和灵魂失去了供养。我们不得不痛苦的活在肉里,灵魂也因此被窒息。然而,随着社会的发展,我们不但吃得好
刘德华流浪地球2新西兰票房突破4700,中国影片开拓国际市场刘德华流浪地球2上映20天,国内票房达到35。19亿,仅次于红海行动,在中国影史排名第11,相信本周末定会实现超越。影片同时积极开拓海外市场,北美票房412万美元,澳大利亚106万
史无前例的跳水女皇伏明霞中国跳水在曾经的过往时代涌现出了无数个跳水女皇,像高敏,郭晶晶,吴敏霞,陈若琳,包括现今的人气选手全红婵,但论真正的跳水女皇又非伏明霞莫属。伏明霞连续参加了三届奥运会,1992年巴
加尔蒂姆巴佩不会出战拜仁,希望梅西和维拉蒂可以上场直播吧2月12日讯在北京时间今天凌晨结束的一场法甲联赛中,巴黎圣日耳曼以13的比分不敌摩纳哥。赛后巴黎主帅加尔蒂在接受PrimeVideo表示,姆巴佩不会出战拜仁,希望届时梅西和维
EXCEL之SUMIF,按学生姓名汇总总成绩功能描述根据学生姓名,计算每位同学的总成绩。原数据样式如上表所示,计算每位学生的总成绩,即语文数学英语的成绩之和。计算公式为SUMIF(A2A10,E2,C2C10)图例公式详解S
从莲塘口岸去香港有多香?免排队,停车免费,8分钟极速通关!在香港与内地恢复全面通关后,有半夜穿拖鞋来深圳吃宵夜的香港人,也有凌晨穿睡衣去办理签注的深圳人,这个周末的口岸,也许会比节假日更加热闹。而且可以预见,不久的将来,罗湖福田深圳湾等几
2022世界技能大赛特别赛金牌选手集体亮相广东又成世赛金牌大户奥秘何在?2022年世界技能大赛特别赛金牌选手羊城晚报全媒体记者梁喻摄羊城晚报全媒体记者周聪通讯员粤仁宣这是广东选手代表中国称雄世界技能之巅的旅途。11名选手,11个项目,分别奔赴四国,取回
年过五十,出现这三个征兆,多半预示着晚年不幸,别不在意俗话说树叶不是一天变黄的。同样的,人的命运也不是一天改变的。有的人,晚年儿孙孝顺,幸福美满,让人羡慕有的人,晚年孤苦无依,凄凄惨惨,令人叹惋。这一切,并不是缘分使然,更不上天安排,