JDK version: 1.8

动态代理中所说的“动态”, 是针对使用Java代码实际编写了代理类的“静态”代理而言的, 它的优势不在于省去了编写代理类那一点编码工作量, 
而是实现了可以在原始类和接口还未知的时候, 就确定代理类的代理行为,当代理类与原始类脱离直接联系后, 就可以很灵活地重用于不同的应用场景之中。

  • 目前Java开发包中包含了对动态代理的支持, 但是其实现只支持对接口的的实现。其实现主要通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。
  • Proxy 类主要用来获取动态代理对象, InvocationHandler 接口用来约束调用者实现。
  • 动态代理是很多框架和技术的基础, spring 的 AOP 实现就是基于动态代理实现的。

Proxy类
Proxy 提供用于创建动态代理类实例的静态方法, 它还是与之创建的所有动态代理类的超类。
介绍一下 Proxy 类中最常用的方法 java.lang.reflect.Proxy#newProxyInstance,

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
...
return cons.newInstance(new Object[]{h});
...
}

该方法返回动态代理类实例. 该方法有三个参数

  • loader: the class loader to define the proxy class. 与原始类的类加载器一致
  • interfaces: the list of interfaces for the proxy class to implement. 原始类实现的接口
  • h: InvocationHandler 实例, 动态代理类实例会调用 InvocationHandler 实例的 invoke 方法

InvocationHandler接口
InvocationHandler 接口中只有一个方法.

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

该方法有三个参数

  • proxy: 动态代理类的实例
  • method: 原始类的 Method 实例
  • args: 被代理 Method 需要的参数

下面通过编写一个简单地动态代理类举例说明:

 1 public class DomainProxyTest {
2
3 interface IGreet {
4
5 void sayHello();
6
7 void sayHi();
8 }
9
10 static class Greet implements IGreet {
11
12 @Override
13 public void sayHello() {
14 System.out.println("Hello World!");
15 }
16
17 @Override
18 public void sayHi() {
19 System.out.println("Hi there!");
20 }
21 }
22
23 static class DynamicProxy implements java.lang.reflect.InvocationHandler {
24
25 Object originalObj;
26
27 Object bind(Object originalObj) {
28 this.originalObj = originalObj;
29 return java.lang.reflect.Proxy
30 .newProxyInstance(originalObj.getClass().getClassLoader(), originalObj.getClass().getInterfaces(), this);
31 }
32
33 @Override
34 public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable {
35 System.out.println("welcome!");
36 return method.invoke(originalObj, args);
37 }
38 }
39
40 public static void main(String[] args) {
41 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
42 IGreet greet = (IGreet) new DynamicProxy().bind(new Greet());
43 greet.sayHello();
44 greet.sayHi();
45 }
46 }

编译 Java 文件:

javac DomainProxyTest.java

 执行 class 文件:

发现生成了一个名称为 $Proxy0.class 的文件, 该文件就是 Java 动态生成的代理类. 反编译看一下其内容:

import DomainProxyTest.IGreet;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException; final class $Proxy0 extends Proxy implements IGreet {
private static Method m1;
private static Method m3;
private static Method m4;
private static Method m2;
private static Method m0; public $Proxy0(InvocationHandler var1) throws {
super(var1);
} public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
} public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final void sayHi() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("DomainProxyTest$IGreet").getMethod("sayHello");
m4 = Class.forName("DomainProxyTest$IGreet").getMethod("sayHi");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}

代码逻辑很简单, 呼应了文章上面对动态代理的描述.

点击链接加入QQ群: 282575808互联网技术交流群】:https://jq.qq.com/?_wv=1027&k=Iw86cqY6

Java进阶--Java动态代理的更多相关文章

  1. Java进阶 | Proxy动态代理机制详解

    一.Jvm加载对象 在说Java动态代理之前,还是要说一下Jvm加载对象的过程,这个依旧是理解动态代理的基础性原理: Java类即源代码程序.java类型文件,经过编译器编译之后就被转换成字节代码.c ...

  2. 使用Java中的动态代理实现数据库连接池

    2002 年 12 月 05 日 作者通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池. 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的 ...

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

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

  4. java中的动态代理机制

    java中的动态代理机制 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现 ...

  5. Java反射和动态代理

    Java反射 反射机制 RTTI 编译器在编译时打开和检查*.class文件 反射机制 运行时打开和检查*.class文件 Java反射常见的方法 java反射的应用 setAccessible(bo ...

  6. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  7. Java学习笔记--动态代理

    动态代理 1.JDK动态代理 JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy ...

  8. 杨晓峰-Java核心技术-6 动态代理 反射 MD

    目录 第6讲 | 动态代理是基于什么原理? 典型回答 考点分析 知识扩展 反射机制及其演进 动态代理 精选留言 Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAnd ...

  9. 十分钟理解Java中的动态代理

    十分钟理解 Java 中的动态代理   一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道 ...

  10. 深度剖析java中JDK动态代理机制

    https://www.jb51.net/article/110342.htm 本篇文章主要介绍了深度剖析java中JDK动态代理机制 ,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定 ...

随机推荐

  1. 内存管理初始化源码5:free_area_init_nodes

    start_kernel ——> setup_arch ——> arch_mem_init ——> |——> bootmem_init  |——> device_tree ...

  2. 解读Java NIO Buffer

    从jdk1.4开始,java中引入了nio包,提供了非阻塞式的网络编程模型,提供网络性能.nio中核心组件有三个:channel.buffer.selector.这里主要探讨buffer的概念和使用. ...

  3. Shell编程(4)

    shell函数 shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数.给这段代码起个名字称为函数名,后续可以直接调用该段代码. 格式 func() { #指定函数名 co ...

  4. Python爬虫开发者工具介绍

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. chrome 开发者工具 当我们爬取不同的网站时,每个网站页面的实现方式各不相同,我们需要对 ...

  5. 5.Topic与Partition

  6. swagger2注解详细说明

    @Api:用在请求的类上,表示对类的说明 tags="说明该类的作用,可以在UI界面上看到的注解" value="该参数没什么意义,在UI界面上也看到,所以不需要配置&q ...

  7. 微信小程序问题汇总

    一.消息推送配置 1.解析失败.请检查信息是否填写正确 服务器地址中不能使用其他的端口号,把端口号去掉,默认就是走80或443端口,另外这个地址需要外网访问,我使用了nat123映射了80端口,这个工 ...

  8. 解析形如(k,v)(k,v)(k,v)字符串

    有时根据需要会将map数据格式化成(k,v)(k,v)(k,v)--字符串,之后需要还原,下面代码实现了还原过程 1 void SplitString(const string& s, vec ...

  9. spring aop 源码分析(二) 代理方法的执行过程分析

    在上一篇aop源码分析时,我们已经分析了一个bean被代理的详细过程,参考:https://www.cnblogs.com/yangxiaohui227/p/13266014.html 本次主要是分析 ...

  10. Go 数组&切片

    数组相关 在Go语言中,数组是一种容器相关的数据类型,用于存放多种相同类型的数据. 数组定义 在定义数组时,必须定义数组的类型以及长度,数组一经定义不可进行改变. 同时,数组的长度是按照元素个数进行统 ...