Java进阶--Java动态代理
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动态代理的更多相关文章
- Java进阶 | Proxy动态代理机制详解
一.Jvm加载对象 在说Java动态代理之前,还是要说一下Jvm加载对象的过程,这个依旧是理解动态代理的基础性原理: Java类即源代码程序.java类型文件,经过编译器编译之后就被转换成字节代码.c ...
- 使用Java中的动态代理实现数据库连接池
2002 年 12 月 05 日 作者通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池. 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的 ...
- java 笔记(3) —— 动态代理,静态代理,cglib代理
0.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口. 代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存 ...
- java中的动态代理机制
java中的动态代理机制 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface).另一个则是 Proxy(Class),这一个类和接口是实现 ...
- Java反射和动态代理
Java反射 反射机制 RTTI 编译器在编译时打开和检查*.class文件 反射机制 运行时打开和检查*.class文件 Java反射常见的方法 java反射的应用 setAccessible(bo ...
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
- Java学习笔记--动态代理
动态代理 1.JDK动态代理 JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy ...
- 杨晓峰-Java核心技术-6 动态代理 反射 MD
目录 第6讲 | 动态代理是基于什么原理? 典型回答 考点分析 知识扩展 反射机制及其演进 动态代理 精选留言 Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAnd ...
- 十分钟理解Java中的动态代理
十分钟理解 Java 中的动态代理 一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道 ...
- 深度剖析java中JDK动态代理机制
https://www.jb51.net/article/110342.htm 本篇文章主要介绍了深度剖析java中JDK动态代理机制 ,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定 ...
随机推荐
- 对比 Redis 中 RDB 和 AOF 持久化
概念 Redis 是内存数据库,数据存储在内存中,一旦服务器进程退出,数据就丢失了,所以 Redis 需要想办法将存储在内存中的数据持久化到磁盘. Redis 提供了两种持久化功能: RDB (Red ...
- 每日一道 LeetCode (48):最长回文子串
每天 3 分钟,走上算法的逆袭之路. 前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee ...
- 聊聊分布式下的WebSocket解决方案
前言 最近王子自己搭建了个项目,项目本身很简单,但是里面有使用WebSocket进行消息提醒的功能,大体情况是这样的. 发布消息者在系统中发送消息,实时的把消息推送给对应的一个部门下的所有人. 这里面 ...
- dubbo学习(十)spring boot整合dubbo
工程搭建与配置 生产者 1.创建一个生产者的spring boot工程,配置好依赖,并把接口实现类文件夹复制到新的工程里 2.pom.xml配置dubbo的相关依赖 <!-- Dubbo Spr ...
- pwnable.kr-mistake-witeup
阅读代码后思路: 实践: 1111111111 其异或值:0000000000 欧克,愉快的结束. 需要经常多看代码,对代码的书写习惯有了解,比如这一块17行一般人书写时都会习惯性加括号的.
- Spring--AOP的见解
AOP是指面向切面编程,与JAVA中的动态代理有很深的渊源. 在使用Spring框架时,AOP编程能简化很多繁杂的步骤,精简代码. 切面:横切关注点(跨越程序中多个模块的功能),被模块化的特殊对象,也 ...
- Linux NSF网络共享盘
服务器安装: yum -y install nfs-utils rpcbind 服务器配置 :vi /etc/exports 例: /root/docs 192.168.1.*(rw,sync,no ...
- 【小白学PyTorch】17 TFrec文件的创建与读取
[新闻]:机器学习炼丹术的粉丝的人工智能交流群已经建立,目前有目标检测.医学图像.时间序列等多个目标为技术学习的分群和水群唠嗑的总群,欢迎大家加炼丹兄为好友,加入炼丹协会.微信:cyx64501661 ...
- #ifdef _DEBUG/ #define new DEBUG_NEW/ #endif的作用
转载:https://blog.csdn.net/minghui_/article/details/80748142 转自:#ifdef _DEBUG #define new DEBUG_NEW #e ...
- Flutter 开发从 0 到 1(三)布局与 ListView
上周日出去玩了,因此没时间写文章.我司加班到 11 点,第二天可以晚上班一个小时,加班到 12 点,可以晚上班两个小时,以此类推,为什么说这个,对的,加班第二天我没有多睡觉,而是起来抓紧时间写文章,好 ...