版权声明:本文为Fighter168原创文章,未经允许不得转载。

 

目录(?)[+]

 

说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等。

记忆特别深刻的是,一次面试中,一位面试官问我,spring的AOP核心采用的设计模式是什么什么模式,阅读过24种设计模式,以及阅读过spring源代码的我竟然答错了,回想起来,真是日了狗了,学过那么多遍的东西都忘记了,结果是装逼失败,自己要狠下心来,把代理都搞懂!

代理模式简述

代理模式是常用的Java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

静态代理

由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。下面通过例子展示。

定义接口

  1. /**
  2. * 定义一个账户接口
  3. *
  4. * @author Fighter
  5. * @date 2016-04-20
  6. *
  7. */
  8. public interface Count {
  9. // 查看账户方法
  10. public void queryCount();
  11. // 修改账户方法
  12. public void updateCount();
  13. }

实现接口

  1. /**
  2. * 委托类(包含业务逻辑)
  3. *
  4. * @author Fighter
  5. * @date 2016-04-20
  6. *
  7. */
  8. public class CountImpl implements Count {
  9. @Override
  10. public void queryCount() {
  11. System.out.println("查看账户方法...");
  12. }
  13. @Override
  14. public void updateCount() {
  15. System.out.println("修改账户方法...");
  16. }
  17. }

添加代理

  1. /**
  2. * 这是一个代理类(增强CountImpl实现类)
  3. *
  4. * @author Fighter
  5. * @date 2016-04-20
  6. *
  7. */
  8. public class CountProxy implements Count {
  9. private CountImpl countImpl;
  10. /**
  11. * 覆盖默认构造器
  12. *
  13. * @param countImpl
  14. */
  15. public CountProxy(CountImpl countImpl) {
  16. this.countImpl = countImpl;
  17. }
  18. @Override
  19. public void queryCount() {
  20. System.out.println("事务处理之前");
  21. // 调用委托类的方法;
  22. countImpl.queryCount();
  23. System.out.println("事务处理之后");
  24. }
  25. @Override
  26. public void updateCount() {
  27. System.out.println("事务处理之前");
  28. // 调用委托类的方法;
  29. countImpl.updateCount();
  30. System.out.println("事务处理之后");
  31. }
  32. }

测试

  1. /**
  2. *测试Count类
  3. *
  4. * @author Fighter
  5. * @date 2016-04-20
  6. *
  7. */
  8. public class TestCount {
  9. public static void main(String[] args) {
  10. CountImpl countImpl = new CountImpl();
  11. CountProxy countProxy = new CountProxy(countImpl);
  12. countProxy.updateCount();
  13. countProxy.queryCount();
  14. }
  15. }

JDK动态代理

特点:只能对实现了接口的类生产代理,不能针对类

定义接口

  1. /**
  2. * 创建业务接口,包含业务可以提供对外的接口
  3. *
  4. * @author Fighter
  5. * @date 2016-04-19
  6. *
  7. */
  8. public interface UserService{
  9. /**
  10. * 目标方法
  11. */
  12. public void add();
  13. }

定义实现类

  1. /**
  2. * 创建业务接口实现类
  3. *
  4. * @author Fighter
  5. * @date 2016-04-19
  6. *
  7. */
  8. public class UserServiceImpl implements UserService{
  9. @Override
  10. public void add() {
  11. System.out.println("----------add----------");
  12. }
  13. }

定义代理

  1. /**
  2. * 自定义简单的Invocation,对接口提供的方法进行增强
  3. *
  4. * @author Fighter
  5. * @date 2016-04-19
  6. */
  7. public class MyInvocationHandler implements InvocationHandler {
  8. //目标对象
  9. private Object target;
  10. /**
  11. * 构造方法
  12. * @param target 目标对象
  13. */
  14. public MyInvocationHandler(Object target) {
  15. super();
  16. this.target=target;
  17. }
  18. <span style="white-space:pre">    </span>/**
  19. * 执行目标对象的方法
  20. */
  21. public Object invoke(Object proxy, Method method, Object[] args)
  22. throws Throwable {
  23. //在目标方法执行前简单打印一下
  24. System.out.println("----------before----------");
  25. //执行目标方法对象
  26. Object result=method.invoke(target, args);
  27. //在目标方法执行之后简单打印一下
  28. System.out.println("----------after----------");
  29. return result;
  30. }
  31. /**
  32. * 获取目标对象的代理对象
  33. * @return 代理对象
  34. */
  35. public Object getProxy(){
  36. return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
  37. this.target.getClass().getInterfaces(),this);
  38. }
  39. }

jdk动态代理测试

  1. public class ProxyTest{
  2. @Test
  3. public void testProxy() throws Throwable{
  4. //实例化目标对象
  5. UserService userService=new UserServiceImpl();
  6. //实例化Invocation
  7. MyInvocationHandler invocationHandler=new MyInvocationHandler(userService);
  8. //根据目标生成代理对象
  9. UserService proxy=(UserService)invocationHandler.getProxy();
  10. //调用代理对象方法
  11. proxy.add();
  12. }
  13. }

CGLIB动态代理示例


JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 

CGLIB是一个强大的高性能的代码生成包。被广泛的许多AOP框架使用,如Spring的AOP和dynaop,为他们提供方法的interceptor(拦截),最流行的是OR Mapping工具hibernate也是使用CGLIB来代理单端的single-ended(多对一和一对一)关联(对集合的延迟抓取是采用其他机制实现)。EsayMock和jMock是通过模仿(moke)对象来测试java代码的包。他们都是通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。

我们先通过demo来快速了解CGLIB的使用示例。

定义实现类

  1. /**
  2. * 这个是没有实现接口的实现类
  3. *
  4. * @author student
  5. *
  6. */
  7. public class BookFacadeImpl {
  8. public void addBook() {
  9. System.out.println("增加图书的普通方法...");
  10. }
  11. }

定义代理

  1. /**
  2. * 使用cglib动态代理
  3. *
  4. * @author student
  5. *
  6. */
  7. public class BookFacadeCglib implements MethodInterceptor {
  8. private Object target;
  9. /**
  10. * 创建代理对象
  11. *
  12. * @param target
  13. * @return
  14. */
  15. public Object getInstance(Object target) {
  16. this.target = target;
  17. Enhancer enhancer = new Enhancer();
  18. enhancer.setSuperclass(this.target.getClass());
  19. // 回调方法
  20. enhancer.setCallback(this);
  21. // 创建代理对象
  22. return enhancer.create();
  23. }
  24. @Override
  25. // 回调方法
  26. public Object intercept(Object obj, Method method, Object[] args,
  27. MethodProxy proxy) throws Throwable {
  28. System.out.println("事物开始");
  29. proxy.invokeSuper(obj, args);
  30. System.out.println("事物结束");
  31. return null;
  32. }
  33. }

编写Cglib测试

  1. public class TestCglib {
  2. public static void main(String[] args) {
  3. BookFacadeCglib cglib=new BookFacadeCglib();
  4. BookFacadeImpl bookCglib=(BookFacadeImpl)cglib.getInstance(new BookFacadeImpl());
  5. bookCglib.addBook();
  6. }
  7. }

总结

当阅读到spring的AOP章节的时候发现其中使用了代理的一些方法,在此复习一下代理的一些实现以及操作。代理-Spring
AOP的核心设计模式。

java代理(静态代理和jdk动态代理以及cglib代理)的更多相关文章

  1. java静态代理和JDK动态代理

    静态代理 编译阶段就生产了对应的代理类 public interface IBussiness { void execute(); } public class BussinessImpl imple ...

  2. 静态代理和jdk动态代理

    要说动态代理,必须先聊聊静态代理. 静态代理 假设现在项目经理有一个需求:在项目现有所有类的方法前后打印日志. 你如何在不修改已有代码的前提下,完成这个需求? 我首先想到的是静态代理.具体做法是: 1 ...

  3. Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景

    我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...

  4. 设计模式——代理模式(静态代理和JDK、CGLib动态代理)

    简介 什么是代理模式? 代理模式就是多一个代理类出来,代替原对象进行一些操作.比如说租房的中介.打官司的律师.旅行社,他们可以代替我们做一些事情,这就是代理. 代理模式的应用场景: 如果已有的方法在使 ...

  5. AOP的底层实现-CGLIB动态代理和JDK动态代理

    AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来 ...

  6. Java动态代理(二)——jdk动态代理

    一.什么是动态代理?代理类在程序运行时创建的代理方式被成为动态代理.动态代理的代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的.相比于静态代理, 动态代理的 ...

  7. Java基础之反射生成JDK动态代理

    在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口.通过这个类和接口可以生成JDK动态代理类或动态代理对象. JDK动态代理例子: / ...

  8. java学习笔记(中级篇)—JDK动态代理

    一.什么是代理模式 相信大家都知道代理商这个概念,在商业中,代理商无处不在.假设你要去买东西,你不可能去找真正的厂家去买,也不可能直接跟厂家提出需求,代理商就是这中间的一桥梁,连接买家和厂商.你要买或 ...

  9. Spring学习之设计模式,动态代理和gclib动态代理

    传统的代理模式是静态代理,也就是在方法区域中写入方法. 而动态代理的作用是,不修改实现类的代码,能够在代码的前后或者抛出异常的前后执行某个方法. 动态代理类的实现 //Interface public ...

随机推荐

  1. C#:终于有人把 ValueTask、IValueTaskSource、ManualResetValueTaskSourceCore 说清楚了!

    目录 1,可用版本与参考资料 2,ValueTask 和 Task 3,编译器如何编译 4,ValueTask 有什么优势 5,ValueTask 创建异步任务 6,IValueTaskSource ...

  2. Spring Cloud 学习 (四) Hystrix & Hystrix Dashboard & Turbine

    在复杂的分布式系统中,可能有几十个服务相互依赖,这些服务由于某些原因,例如机房的不可靠性.网络服务商的不可靠性等,导致某个服务不可用 . 如果系统不隔离该不可用的服务,可能会导致整个系统不可用.Hys ...

  3. 使用douban源下载python包

    需求 python默认使用国外源下载依赖包,由于一些其它因素(例如网络差了,国外机器炸了,我们强大的祖国了...)经常导致下载安装失败,so出现了以豆瓣为主的国内下载源 如何使用豆瓣进行下载 豆瓣下载 ...

  4. 老猿学5G专栏完结说明

    老猿学5G是因为工作原因促成的,主要目的是为了研究5G的计费架构相关内容,到今天为止,基本上达成目标,因此这个专栏基本上告一段落了. 回想这2个多月的日子,从一个对5G相关知识完全不熟悉的小白,到现在 ...

  5. 老猿学5G扫盲贴:中国移动的5G计费架构解读

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.引言 在<老猿学5G扫盲贴:3GPP中的 ...

  6. PyQt(Python+Qt)学习随笔: QAbstractItemView的dragDropMode属性

    老猿Python博文目录 老猿Python博客地址 一.概述 dragDropMode属性用于控制视图拖放事件的处理方式,其类型为枚举类型DragDropMode. 二.枚举类型DragDropMod ...

  7. 深入理解.NET/WPF内存泄漏

    众所周知,内存管理和如何避免内存泄漏(memory leak)一直是软件开发的难题.不要说C.C++等非托管(unmanaged)语言,即使是Java..NET等托管(managed)语言,尽管有着完 ...

  8. 笔记-[JSOI2011]柠檬

    笔记-[JSOI2011]柠檬 [JSOI2011]柠檬 \(f_i\) 表示到第 \(i\) 只贝壳最多可以换得的柠檬数. 令 \(c_i=\sum_{h=1}^i[s_h=s_i]\). \[\b ...

  9. POWER BI 基于 ODBC 数据源的配置刷新-以Amazon Redshift为例

    POWER BI 基于 ODBC 数据源的配置刷新-以Amazon Redshift为例 Powerbi 有多种数据源连接,可以使用它们连接到不同数据源. 如果在 Power BI Desktop 的 ...

  10. linux下/etc/profile /etc/bashrc /root/.bashrc /root/.bash_profile这四个配置文件的加载顺序

    目录 一.关于linux配置文件 二.验证四个配置文件的加载顺序 三.结论 一.关于linux配置文件 1.linux下主要有四个配置文件:/etc/profile ./etc/bashrc ./ro ...