Java动态代理

为什么使用动态代理

当需要对某个类的某个方法进行修饰(增强)的时候,可以使用继承、装饰者模式和动态代理。

三种方式局限性:

  1. 继承:增强的对象不能改变,增强的内容不能改变。
  2. 装饰者模式:增强的对象不能改变,增强的内容能改变。
  3. 动态代理:增强的对象可以改变,增强的内容可以改变。

使用动态代理可以更加灵活地提高代码的复用程度。

举个栗子:
对于计算机教师这个类,有个teach()方法,时过境迁,旧的教学模式可能已经不适合高速发展的计算机行业了,因此在使用这个teach()方法可能需要前面或者后面要增加一点东西。但是对于老旧的项目,我们很难去理解前人的写法和思维方式,因此不能轻易修改他们的代码,所以我们可以使用代理去实现对teach()方法的增强(我这里分为前置增强和后置增强)。

如何使用动态代理

Object Proxy.newInstance(ClassLoader loader, Class[] interfaces, InvocationHandler ih)

  1. loader:类加载器,将类加载到内存当中。
  2. interfaces:代理对象要实现的接口。
  3. ih:InvocationHandler,其中实现invoke()方法,来实现对目标对象的增强。
  4. 返回值:jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象

InvocationHandler接口

该接口需要实现invoke()方法。

Object invoke(Object proxy, Method method, Object[] args)

  1. proxy:代理对象。
  2. method:代理对象使用的目标方法。
  3. args:目标方法的参数。
  4. 返回值:method方法的返回值。

在使用代理对象使用某个方法的时候,会调用生成代理对象时候传入的InvocationHandler的invoke()方法,因此可以在这个invoke()里面写需要增强的内容。

Demo

先给出两个接口和一个实现类

public interface Subject {public int outPut(int num);
}
public interface BSubject {public int outPut2(int num);
}
public class realSubject implements Subject, BSubject {@Overridepublic int outPut(int num) {System.out.println("outPut " + String.valueOf(num) + " people");return num;}@Overridepublic int outPut2(int num) {System.out.println("outPut2 " + String.valueOf(num) + " people");return num;}
}

使用动态代理

前置增强接口:

public interface BeforeAdvance { // 前置增强接口public void before();
}

后置增强接口:

public interface AfterAdvance { // 后置增强接口public void after();
}

创建代理工厂,可以更加方便调用:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyFactory {private Object targetObject; // 目标代理对象private BeforeAdvance beforeAdvance; // 前置增强private AfterAdvance afterAdvance; // 后置增强public Object createFactory() {ClassLoader loader = this.getClass().getClassLoader(); // 加载.class到内存Class[] interfaces = targetObject.getClass().getInterfaces(); // 得到realSubject所有接口(Waiter), 给代理对象提供了一组接口,这个代理对象就会实现这组接口,InvocationHandler ih = new InvocationHandler() {@Override// proxy 是代理对象,是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象// Method 是目标对象需要增强的方法// args是实参public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(beforeAdvance != null) { // 调用前置增强方法beforeAdvance.before();}Object result = method.invoke(targetObject, args); // 通过反射调用目标代理对象的目标方法, result是目标方法的返回值if(afterAdvance != null) { // 调用后置增强方法afterAdvance.after();}return result;}};return Proxy.newProxyInstance(loader, interfaces, ih); // 得到一个代理对象}public AfterAdvance getAfterAdvance() {return afterAdvance;}public void setAfterAdvance(AfterAdvance afterAdvance) {this.afterAdvance = afterAdvance;}public BeforeAdvance getBeforeAdvance() {return beforeAdvance;}public void setBeforeAdvance(BeforeAdvance beforeAdvance) {this.beforeAdvance = beforeAdvance;}public Object getTargetObject() {return targetObject;}public void setTargetObject(Object targetObject) {this.targetObject = targetObject;}
}

示例:

import org.junit.Test;public class Demo {@Testpublic void fun() {ProxyFactory proxyfactory = new ProxyFactory();// 代理的目标对象proxyfactory.setTargetObject(new realSubject());// 前置增强接口实现proxyfactory.setBeforeAdvance(new BeforeAdvance() {@Overridepublic void before() {System.out.println("hello");}});// 后置增强接口实现proxyfactory.setAfterAdvance(new AfterAdvance() {@Overridepublic void after() {System.out.println("byebye");}});// 生成对Subject接口的实现类对象Subject subject = (Subject) proxyfactory.createFactory(); // 通过newInstance()得到一个代理对象,这个代理对象实现了Subject接口,因此可以强转为Subject接口类。BSubject subject2 = (BSubject) proxyfactory.createFactory();Object result = subject.outPut(100); // 对应InvocationHandler的invoke方法:subject为proxy, outPut为method, 参数为argsSystem.out.println(result);System.out.println("-----");Object result2 = subject2.outPut2(50);System.out.println(result2);}
}输出:
hello
outPut 100 people
byebye
100
-----
hello
outPut2 50 people
byebye
50

在这里面,只要使用反射,method.invoke()就可以调用代理的目标对象的该方法,然后实现前置增强BeforeAdvance接口和后置增强AfterAdvance接口,就可以实现对方法内容的增强了。
其中不同接口的不同实现方法都可以重用BeforeAdvance和AfterAdvance。
对于不同的增强对象也可以使用,只要targetObject改一下就可以了。

附上一篇讲的不错的文章

转载于:https://www.cnblogs.com/fightfordream/p/7965479.html

Java学习之动态代理相关推荐

  1. 学习spring必须java基础知识-动态代理

    2019独角兽企业重金招聘Python工程师标准>>> Spring AOP使用动态代理技术在运行期织入增强的代码,为了揭示Spring AOP底层的工作机理,有必要对涉及到的Jav ...

  2. java 笔记(3) —— 动态代理,静态代理,cglib代理

    0.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口. 代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存 ...

  3. Java设计模式-----Cglib动态代理(Cglib Proxy)

    接上文:4.2Java设计模式-----JDK动态代理(Dynamic Proxy) Cglib动态代理 百度百科:Cglib是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java ...

  4. 仿照java的jdk动态代理实现go语言动态代理

    仿照java的jdk动态代理实现go语言动态代理 通过学习java的jdk动态代理和Cglib动态代理,仿照jdk动态代理用go实现了一个简单的动态代理 结构型模式 代理模式 代理模式中分为静态代理和 ...

  5. 吃透Java中的动态代理

    动态代理在Java中是很重要的一部分,在很多框架中都会用到,如Spring中的AOP.Hadoop中的RPC等.为此在这把我对Java中的动态代理的理解分享给大家,同时写了一个模拟AOP编程的实例.( ...

  6. Java基础:动态代理

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 概述 在运行时,动态创建一组指定的接口的实现类对象(代理对象)! 代理是实现AOP(面向切面编程)的核 ...

  7. Java se之动态代理

    转载自 Java se之动态代理 jdk动态代理: jdk动态代理是 需要提供一个实现了InvocationHandler接口的处理类: 通过Proxy的newProxyInstance()方法,参数 ...

  8. java | 什么是动态代理?

    java | 什么是动态代理? 代理模式在 Java 领域很多地方都有应用,它分为静态代理和动态代理,其中 Spring AOP 就是动态代理的典型例子.动态代理又分为接口代理和 cglib (子类代 ...

  9. 码农翻身——Java帝国之动态代理

    已经快三更天了, Java帝国的国王还在看着IO大臣的奏章发呆,他有点想不明白, 帝国已经给臣民了提供了这么多的东西,他们为什么还不满意呢? 集合.IO.反射.网络.线程.泛型.JDBC ...... ...

最新文章

  1. 父亲节遇上端午节,你难道不回家吗?
  2. java.io.NotSerializableException:异常
  3. HTML5 details 标签
  4. 3D 投影矩阵学习1
  5. nova7修屏逛校园2021-07-07
  6. [android] AndroidManifest.xml【 manifest - permission-tree 和 manifest - permission-group】
  7. SpringCloud Alibaba 框架下公司架构图
  8. 论文笔记之:Deep Attention Recurrent Q-Network
  9. java 注解 target_详解JDK 5 Annotation 注解之@Target的用法
  10. php框架 swoop_PHP Form Validation
  11. 让接口性能轻松翻倍之10条经验
  12. JDK官方文档(包含所有版本)
  13. DELL新版BIOS重装系统win10
  14. Web前端之响应式 Gulp 中文网
  15. 微信小程序存在的风险_警惕,你的微信小程序可能面临着风险!
  16. Nose | 超轻的单元测试框架-精通
  17. 5c标准第二语言,美国语言教学5C标准对中文作为第二语言教学课堂的启示
  18. 【c】三角形图形输入 6*11 看懂这一个以后打印图形信手nian来
  19. Ubuntu 11.04 安装后要做的20件事情
  20. 组态王图素制作_组态王实例教程入门

热门文章

  1. Dos中通过Pause来阻止窗口运行就关闭
  2. Spring Boot 2发送邮件手把手图文教程
  3. 无责任书评:每个Java程序员都应该深入理解Java虚拟机!
  4. MyBatis+Spring MVC开发指南(一)
  5. Spring Boot 配置加载顺序详解
  6. 《Spring Cloud Netflix官方文档》1.服务发现:Eureka客户端
  7. Hibernate:根据配置文件自动生成表结构的2种方式
  8. amazon mws api 获取所有产品_致跨境电商新卖家 - 如何确定一个产品的市场容量?...
  9. 专家解读 | 数据中心,从“电老虎”走向“数字经济发动机”
  10. 腾讯天津数据中心余热回收应用初探