在对象的一个业务方法完成之后, 有时候我们可能需要去添加一些新的功能(前置校验等). 但我们又不想更改原来的代码 , 代理模式就为我们提供了一种解决方案 .

1 . 代理模式的定义

代理模式就是在不改变原有代码的基础上 , 实现对目标对象的功能扩展 .

以现实的情况为例 , 目前有一个艺人, 她会表演和唱歌 . 现在想扩展一个行为来为这个艺人来接通告 , 通常情况下我们是不想把这个业务交给原来的艺人去做的, 毕竟也不是她的职责 . 这时候我们就可以引入一个代理对象 , 即经纪人 . 经纪人去来完成收发通告的一些扩展业务 , 但需要表演时 , 仍然要经纪人(代理对象)通知艺人(目标对象)来完成功能 .

代理模式分为静态代理 , 动态代理(根据实现方式又分为JDK动态代理和CGLIB动态代理) .

2 . 代理模式的特点

不影响原有业务代码实现新功能扩展

3 . 代理模式的主要角色

  • 抽象接口 : 即目标对象实现的接口 , 在静态代理和JDK代理中是必备角色
  • 目标对象 : 就是实现了具体业务的类 , 在代理模式下仍然需要目标对象来完成原本业务
  • 代理对象 : 目标对象的代理类 , 对目标对象的原有业务增加扩展操作

4 . 代理模式的应用场景

最经典的就是Spring中的AOP , 它的原理就是通过动态代理来完成

5 . 代码实现

5.1 静态代理

静态代理就是通过实现与目标相同的接口 , 并注入原本的代理目标对象 . 在重写的方法中完成扩展 , 并调用目标对象来实现原有操作

package com.xbz.xstudy.shejimoshi.proxy.targetObject;/*** @title 需要代理的目标接口(艺人)* @author Xingbz* @createDate 2019-4-23*/
public interface ActorInterface {void show();
}
package com.xbz.xstudy.shejimoshi.proxy.targetObject;/*** @title 需要代理的目标实现对象(艺人)* @author Xingbz* @createDate 2019-4-23*/
public class ActorInterfaceImpl implements ActorInterface {@Overridepublic void show() {System.out.println("艺人完成了一场表演 ~ ");}
}
package com.xbz.xstudy.shejimoshi.proxy.staticState;import com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterface;/*** @title 静态代理对象(经纪人)* @author Xingbz* @createDate 2019-4-23*/
public class ActorProxy implements ActorInterface {private ActorInterface actor;public ActorProxy(ActorInterface actor) {this.actor = actor;}@Overridepublic void show() {System.out.println("[静态代理]经纪人为艺人接了通告");actor.show();//通知艺人自身来完成行为System.out.println("[静态代理]经纪人为艺人完成通告");}
}
package com.xbz.xstudy.shejimoshi.proxy.staticState;import com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterface;
import com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterfaceImpl;/*** @title 静态代理测试类* @author Xingbz* @createDate 2019-4-22*/
public class Demo {public static void main(String[] args){ActorInterface actor = new ActorInterfaceImpl();actor.show();//正常执行方法ActorInterface actorProxy = new ActorProxy(actor);actorProxy.show();//实际还是actor自身的操作, 但在方法执行前后会有一些经纪人的代理操作}
}

静态代理的优点 : 可以做到不对目标对象进行任何修改的前提下 , 将目标对象实现功能扩展

静态代理的缺点 : 因为代理对象需要实现与目标对象一样的接口 , 会导致代理类非常繁多 , 不易维护 . 并且如果接口增加方法 , 目标对象和代理对象都需要变动

5.2 JDK动态代理

JDK动态代理就是指动态的在内存中创建代理对象 . 不用实现任何借口 , 通过传入的目标对象和指定接口 , 利用反射调用JDK API动态的创建代理类

package com.xbz.xstudy.shejimoshi.proxy.dynamic.jdk;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** @title 动态代理Handler* @author Xingbz* @createDate 2019-4-23*/
public class ProxyHandler implements InvocationHandler {private Object targetObject;//用于接收代理目标实际对象public ProxyHandler(Object targetObject) {this.targetObject = targetObject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("[JDK动态代理]经纪人为艺人接了通告");method.invoke(targetObject, args);//通知艺人自身来完成行为System.out.println("[JDK动态代理]经纪人为艺人完成通告");return proxy;}
}
package com.xbz.xstudy.shejimoshi.proxy.dynamic.jdk;import com.xbz.xstudy.shejimoshi.proxy.ProxyClassOutUtil;
import com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterface;
import com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterfaceImpl;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;/*** @title JDK动态代理测试类* @author Xingbz* @createDate 2019-4-23*/
public class Demo {public static void main(String[] args){ActorInterface actor = new ActorInterfaceImpl();InvocationHandler actorHandler= new ProxyHandler(actor);ActorInterface actorProxy = (ActorInterface) Proxy.newProxyInstance(ActorInterface.class.getClassLoader(), new Class[]{ActorInterface.class}, actorHandler);actorProxy.show();}
}

JDK动态代理的优点 : 无需实现接口 , 免去编写很多代理类的繁琐

JDK动态代理的缺点 : 代理对象不需实现接口 , 但目标对象必须实现接口 , 如果目标对象没有接口的话就不能使用JDK动态代理了

5.3 CGLIB动态代理

cglib是通过扫描该类及其父类中的所有public方法 , 通过asm动态生成该类的子类字节码 . 在子类中重写了该类的所有方法 , 加入扩展逻辑 , 然后返回该子类的实例作为代理类 . 即是说 , cglib是通过该类的子类作为代理类来实现代理操作的 , 所以代理目标中的非public方法及static/final修饰的方法 , 不能实现代理 .

asm是一个小而快的字节码处理框架 , 它负责生成从代理目标类中扫描出的方法字节码 , 并将这些字节码暂存在内存中 . 然后我们通过某种方式将这些字节码转换为class,最勇利用反射创建代理类的实例返回 .

使用该方法需要引入cglib和asm依赖 , spring已经内嵌了这两个jar包 . 如果项目中有用到spring则无需再引入 .

package com.xbz.xstudy.shejimoshi.proxy.targetObject;/*** @title 未实现接口的代理目标对象(主播)* @author Xingbz* @createDate 2019-4-23*/
public class Anchor {public void sing(String song) {System.out.println("主播唱了一首歌 : " + song);}
}
package com.xbz.xstudy.shejimoshi.proxy.dynamic.cglib;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @title CGLIB动态代理Inerceptor* @description* @author Xingbz* @createDate 2019-4-23*/
public class MyMethodInerceptor implements MethodInterceptor {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("[CGLIB动态代理]助理为主播选了一首歌");Object result = methodProxy.invokeSuper(o, objects);System.out.println("[CGLIB动态代理]助理带头为主播刷礼物");return result;}
}
package com.xbz.xstudy.shejimoshi.proxy.dynamic.cglib;import com.xbz.xstudy.shejimoshi.proxy.ProxyClassOutUtil;
import com.xbz.xstudy.shejimoshi.proxy.targetObject.Anchor;
import org.springframework.cglib.proxy.Enhancer;/*** @title CGLIB动态代理测试类* @author Xingbz* @createDate 2019-4-23*/
public class Demo {public static void main(String[] args){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(Anchor.class);enhancer.setCallback(new MyMethodInerceptor());Anchor anchor = (Anchor) enhancer.create();anchor.sing("今天是个好日子");}
}

CGLIB动态代理的优点 : 无需目标对象实现接口

CGLIB动态代理的缺点 : 非public , 或statsi/final修饰的方法无法被代理

6 . 总结

三种代理各有优缺点和适用范围 , 主要看目标是否实现了接口 . 在Spring框架的AOP中 , 如果纳入容器的bean有实现接口 , 则用JDK代理 . 如果没有实现接口 , 则用CGLIB代理

JAVA设计模式 - 代理模式相关推荐

  1. java设计模式代理模式_Java中的代理设计模式

    java设计模式代理模式 代理对象或代理对象为另一个对象提供占位符,以控制对该对象的访问. 代理充当原始对象的轻量级版本或简化版本. 它支持与原始对象相同的操作,但可以将那些请求委托给原始对象以实现它 ...

  2. Java设计模式(代理模式-模板方法模式-命令模式)

    Java设计模式Ⅴ 1.代理模式 1.1 代理模式概述 1.2 静态代理 1.2.1 静态代理概述 1.2.2 代码理解 1.3 动态代理之JDK代理 1.3.1 动态代理之JDK代理概述 1.3.2 ...

  3. Java设计模式-代理模式笔记

    代理模式 0 什么是代理模式 理解方式1 理解方式2 1 静态代理 1.1 代码实现 1.2 方法解读 1.3 优缺点 2 动态代理 2.1 具体实现 2.2 方法解读 2.3 注意 3 Cglib代 ...

  4. 通俗易懂说java设计模式-代理模式

    基本概念 代理模式,和我们在生活中所理解的"代理"思想并没有太大的区别.代理模式的实现需要我们设计一个代理类,在不直接访问被代理对象的前提下,通过代理类实现对被代理对象的间接访问, ...

  5. JAVA设计模式--代理模式(静态)

    目录 一.什么是代理模式 二.静态代理模式的结构 三.静态代理模式应用举例 应用一 应用二 四.代理模式的应用场景 五.静态代理模式的特点 一.什么是代理模式 代理(Proxy)模式为其他对象提供一种 ...

  6. Java设计模式—代理模式

    1. 什么是代理模式? 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问. 2. 代理模式有什么好处? 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标 ...

  7. java设计模式-代理模式初探

    根据圣思园的视频,整理的java代理模式. 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间 ...

  8. Java设计模式——代理模式

    文章目录 1.简介 2.推荐实现案例 3.优缺点 3.1 优点 3.2 缺点 4.应用场景 5.注意事项 6.拓展 6.1 普通代理 6.2 强制代理 6.3 代理类的个性 6.4 动态代理 7.最佳 ...

  9. Java设计模式--代理模式

    1. 代理模式的引入 王大爷借了小李1.5亿,小赖是个无赖横竖就是不还钱,王大爷身子弱讨不回钱就请了讨债公司的小强,最后小强通过一系列**(过于残暴被打码了)的手段帮助王大爷讨回欠款.完事后还帮王大爷 ...

最新文章

  1. python的unittest測试框架的扩展浅谈
  2. 从零开始一步一步搭建Ubuntu Server服务器、修改数据源、安装Docker、配置镜像加速器、Compose部署Gitlab服务
  3. 科大星云诗社动态20210508
  4. 将null转换成数组_把数组里面的值为 null 的转换为字符串 - - ,你们的方法都是什么呢?...
  5. 2022年版955不加班公司名单!
  6. SAP云平台上Redis dashboard提供的功能一览
  7. php 放大镜,图片放大镜效果实战总结
  8. leetcode - 740. 删除与获得点数
  9. GPU Pro 2 ------ Volume Decals
  10. 5月购机指南!新机流畅度排行榜:第一名实至名归
  11. EMC-- DFC --Sessions and Session Managers
  12. HTMO DOM部分---小练习;列表之间移动、日期选择、好友选中、滑动效果、滚动条效果、飞入飞出效果。...
  13. java入门书籍《java语言程序设计 基础篇》原书第10版 强烈推荐
  14. 微博android4.1.2,微博客户端Fuubo
  15. 六安牌照上海浦东验车
  16. 书摘—吃我吃我:38种改善情绪和恢复精力的神奇食材
  17. python operator用法_说说 Python 中的 Operator 模块
  18. 读书寄语:蒲苇时韧、磐石永坚
  19. oracle北京时区,Oracle中的时区偏移
  20. Airsim+UnrealEngine4 搭建无人车/无人机自动驾驶仿真环境

热门文章

  1. Sublime 格式化代码 快捷键以及插件使用
  2. hdu2243考研路茫茫——单词情结
  3. C++关键字--volatile
  4. 写在开通博客的第一天
  5. matlab2008设置子函数断点无效,程序不在断点处停止
  6. Vue (响应式原理-模拟-4-Dep)
  7. java获取字典所有的key_JAVA脱水学习-java集合介绍,常用集合类
  8. centos 安装mysql扩展_centos php安装mysql扩展的方法
  9. SpringMVC、Spring、Mybatis框架整合及使用
  10. weblogic服务器连接池配置细节