Java 代理模式

什么是代理

代理是一种设计模式,它的核心思想,是将对目标的访问转移到代理对象上。这样做的好处就是,目标对象在不改变代码的情况下,可以通过代理对象加一些额外的功能。这是一种编程思想,在不改变原有代码的情况下,通过代理增加一些扩展功能。

代理过程如图所示,用户访问代理对象,代理对象通过访问目标对象,来达到用户访问目标对象的目的,

代理模式包含一下三个角色:

  • ISubject:接口对象,该接口是对象和它的代理共用的接口。

  • TargetSubject:目标对象,是实现抽象主题接口的类。

  • Proxy:代理角色,内部含有对目标对象TargetSubject的引用,从而可以操作真实对象。代理对象提供与目标对象相同的接口,以便在任何时刻都能代替目标对象。同时,代理对象可以在执行目标对象操作时,附加其他的操作,相当于对真实对象进行封装。

常见的代理模式分为静态代理和动态代理,动态代理在Java中的实现分为JDK动态代理和cglib代理。

静态代理

在之前已经说过,在代理模式中有三个角色,一是目标接口,二是目标对象,三是代理对象。

现在以具体代码来实现,首先是目标接口如下:

 public interface IBlogService {void writeBlog();
}

目标对象实现了目标接口,代码如下:

public class BlogService implements IBlogService {@Overridepublic void writeBlog() {System.out.println("i'm writing...");}
}

静态代理对象,通过构造方法获取到目标对象,并实现了目标接口,在目标接口的方法里调用了目标对象的方法,代码如下:

public class BlogStaticProxy implements IBlogService{private IBlogService blogService;public BlogStaticProxy(IBlogService blogService) {this.blogService = blogService;}@Overridepublic void writeBlog() {System.out.println("start writing...");blogService.writeBlog();System.out.println("end writing...");}
}

测试:

public class TestStaticProxy {public static void main(String[] args) {IBlogService target = new BlogService();BlogStaticProxy proxy = new BlogStaticProxy(target);proxy.writeBlog();}
}

start writing…

i’m writing…

end writing…

静态代理,在不修改目标对象的情况下,可以通过代理对象做额外的扩展功能。但静态方法不是很灵活,如果目标接口的代码修改,目标对象和代理对象都需要修改。

动态代理在一定程度上避免这种情况,动态代理不需要代理对象实现目标接口,并且上在java 虚拟机的内存中动态的生成代理对象

Jdk动态对象

Jdk的动态代理由Proxy这个类来生成,它有三个参数:

  • ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的

  • Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型

  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入

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

Jdk的动态代理代码如下:

 public class JdkBlogProxyFactory {private Object target;public JdkBlogProxyFactory(Object target) {this.target = target;}public Object newInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),(proxy, method, args) -> {System.out.println("start writing");Object o = method.invoke(target, args);System.out.println("end writing");return o;});}
}

测试类:

public class TestJdkProxy {public static void main(String[] args) {IBlogService target = new BlogService();System.out.println(target.getClass());// 给目标对象,创建代理对象IBlogService proxy = (IBlogService) new JdkBlogProxyFactory(target).newInstance();// class $Proxy0   内存中动态生成的代理对象System.out.println(proxy.getClass());// 执行方法   【代理对象】proxy.writeBlog();}
}

控制台打印如下:

class com.forezp.proxy.BlogService
class com.sun.proxy.$Proxy0
start writing
i'm writing...
end writing

CGLib动态代理

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

CglibBlogFactory代理工厂类如下:

public class CglibBlogFactory implements MethodInterceptor {private Object target;public CglibBlogFactory(Object target) {this.target = target;}//给目标对象创建一个代理对象public Object getProxyInstance() {//1.工具类Enhancer en = new Enhancer();//2.设置父类en.setSuperclass(target.getClass());//3.设置回调函数en.setCallback(this);//4.创建子类(代理对象)return en.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("start writing...");//执行目标对象的方法Object returnValue = method.invoke(target, objects);System.out.println("end writing...");return returnValue;}
}

测试类:

public class TestCglib {public static void main(String[] args) {IBlogService target = new BlogService();//代理对象IBlogService proxy = (IBlogService) new CglibBlogFactory(target).getProxyInstance();//执行代理对象的方法proxy.writeBlog();}
}

运行程序,控制台打印:

start writing...
i'm writing...
end writing...

参考资料

http://www.cnblogs.com/cenyu/p/6289209.html

http://blog.csdn.net/yakoo5/article/details/9099133/

关于代理。谢谢方志朋相关推荐

  1. Nginx配置反向代理,一篇搞定!

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/zxd1435513775/article/ details/102508463 一.引言 其他话 ...

  2. 动态代理竟然如此简单!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 这篇文章我们来聊一下 Java 中的动态代理. 动态代理在 ...

  3. nginx 反向代理和负载均衡策略实战案例

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:glmapper https://juejin.im/pos ...

  4. 懂点 Nginx 反向代理与负载均衡,是面试加分项没有之一

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 学到老活到老 前端圈一直很新,一直要不停的学习,而且在进入大厂的路上,还要求熟悉一门后台语言等等 ...

  5. 企业服务内部接口校验方案

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:低调的码农 juejin.im/post/68449 ...

  6. 一位后端妹纸的面试总结(美团+阿里+携程+58+贝贝+招银+华为+....)

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:倾听潮汐 来源:nowcoder.com/discuss/5 ...

  7. 一套基础自动化部署搭建过程

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:LoyaltyLu segmentfault.com/a/1 ...

  8. SpringBoot+RabbitMQ ,保证消息100%投递成功并被消费(附源码)

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:rrd.me/f2cxz 一.先扔一张图 说明: 本文涵盖了 ...

  9. 淘宝服务端高并发分布式架构演进之路

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 1. 概述 本文以淘宝作为例子,介绍从一百个并发到千万级并发情况下服务端的架构的演进过程,同时列 ...

  10. 最近面试 Java 后端开发的感受!

    点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! 首发:cnblogs.com/JavaArchitect/p/10011253.html 上周,密 ...

最新文章

  1. lvm自动扩容到固定分区脚本
  2. RV1108开发环境搭建
  3. java数组创建后大小能改变吗,在Java中,数组创建成功以后,其大小(??? )(能/不能)改变...
  4. 难学的十大编程语言,C++位居第二,它才是第一名!
  5. 工行高级经理林承军:工行基于 MySQL 构建分布式架构的转型之路
  6. Spring:@AutoConfigurexxx注解-控制配置类的加载顺序
  7. java appt,(转从ajava)打开ppt
  8. 面向对象的设计原则-类设计原则
  9. a3图纸标题栏尺寸标准_求标准CAD图纸(A0、A1、A2、A3、A4)图框(外框、内框)、标题栏及明细栏大小样式字体是多大?...
  10. ir指令、立即数的作用_计算机系统概论-笔记
  11. 想转行学IT,Java怎么样?
  12. Oracle (03)分组子句.where条件 与 having条件的区别.子查询.DDL.DML.数据的增删改.TCL
  13. 【python初学者日记】输入年份:判断是否闰年:闰年:yyyy是闰年,这年有366天;yyyy是平年,这年有365天
  14. 从零开始搭建公司域环境(二):服务器安装域控并实现客户端加域登陆
  15. 【汇智学堂】基于Socket实现的网络版梅花易数一撮金游戏
  16. 一、Azure Kinect 传感器 SDK 下载——Azure Kinect DK入门
  17. sql登录名和用户名_通过分配角色和权限来移动或复制SQL登录名
  18. 因果推理(五):随机试验和可识别
  19. 硬件:宽带猫(光猫)的基础知识
  20. html网页宽度自动适应手机屏幕

热门文章

  1. 故宫回应灯会票秒光:3500人约成功 没票别信黄牛
  2. 微信小程序之蓝牙打印
  3. 微信小程序-视频教程-链接地址
  4. SolidWorks有限元分析流程
  5. 使用Python破解通达信股票数据
  6. 数字电路基础知识——时序逻辑电路之时序逻辑分析方法
  7. nrf52840蓝牙协议栈主机一拖八
  8. 测试过程中如何解决测试账号问题
  9. ProgressBar 圆形进度条
  10. Could not read JSON: Cannot construct instance of `java.util.ArrayList$SubList`