JDK动态代理优化

master
linlei 2024-04-10 17:05:21 +08:00
parent 7a5b7f77ee
commit d2c74eccf5
1 changed files with 16 additions and 86 deletions

View File

@ -1,15 +1,15 @@
## JDK动态代理 ## JDK动态代理
- [JDK动态代理](#JDK动态代理) - [JDK动态代理](#jdk动态代理)
- [一、基本信息](#一基本信息) - [一、基本信息](#一基本信息)
- [二、知识储备](#二知识储备) - [二、知识储备](#二知识储备)
- [三、基本描述](#三基本描述) - [三、基本描述](#三基本描述)
- [四、主要功能](#四主要功能) - [四、主要功能](#四主要功能)
- [五、接口源码](#五接口源码) - [五、最佳实践](#五最佳实践)
- [六、主要实现](#六主要实现) - [六、源码分析](#六源码分析)
- [七、最佳实践](#七最佳实践) - [七、与其他组件的关系](#七与其他组件的关系)
- [八、与其他组件的关系](#八与其他组件的关系) - [八、常见问题](#八常见问题)
- [九、常见问题](#九常见问题)
### 一、基本信息 ### 一、基本信息
@ -59,74 +59,7 @@ JDK动态代理是一种在运行时生成代理类的机制它基于接口
+ 动态代理是AOP面向切面编程的基础之一可以通过动态代理实现切面的横切关注点将应用程序核心业务逻辑与横切关注点分离开来提高了代码的可维护性和灵活性。 + 动态代理是AOP面向切面编程的基础之一可以通过动态代理实现切面的横切关注点将应用程序核心业务逻辑与横切关注点分离开来提高了代码的可维护性和灵活性。
### 五、接口源码 ### 五、最佳实践
在Java JDK 中的动态代理机制中,`Proxy` 类提供了静态方法 `newProxyInstance`,用于动态生成代理对象。通过传入类加载器、接口数组和 `InvocationHandler` 对象,该方法在运行时生成一个代理对象。内部实现使用了反射机制,通过调用代理类的构造函数,将 `InvocationHandler` 对象传递给代理对象。
```java
public class Proxy implements java.io.Serializable {
protected InvocationHandler h;
private Proxy() {
}
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
// ... [代码部分省略以简化]
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
Objects.requireNonNull(h);
final Class<?> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();
/*
* Look up or generate the designated proxy class and its constructor.
*/
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
return newProxyInstance(caller, cons, h);
}
// ... [代码部分省略以简化]
private static Object newProxyInstance(Class<?> caller, // null if no SecurityManager
Constructor<?> cons,
InvocationHandler h) {
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (caller != null) {
checkNewProxyPermission(caller, cons.getDeclaringClass());
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException | InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
}
}
// ... [代码部分省略以简化]
}
```
### 六、最佳实践
使用 JDK 动态代理的基本流程。首先,创建目标对象 `MyService` 的实例,然后获取目标对象的类信息。接着,通过调用 `Proxy.newProxyInstance` 方法创建代理对象,传入目标对象的类加载器、实现的接口以及调用处理器。最后,通过代理对象调用方法,实际上会调用 `MyInvocationHandler` 中的 `invoke` 方法来处理方法调用,并在方法执行前后添加额外的逻辑。 使用 JDK 动态代理的基本流程。首先,创建目标对象 `MyService` 的实例,然后获取目标对象的类信息。接着,通过调用 `Proxy.newProxyInstance` 方法创建代理对象,传入目标对象的类加载器、实现的接口以及调用处理器。最后,通过代理对象调用方法,实际上会调用 `MyInvocationHandler` 中的 `invoke` 方法来处理方法调用,并在方法执行前后添加额外的逻辑。
@ -194,11 +127,9 @@ hello world
After method execution After method execution
``` ```
### 、源码分析 ### 、源码分析
> com.sun.proxy.$Proxy0 类是通过 Arthas 运行时编译生成的。Arthas 是一个强大的 Java 诊断工具,可以在运行时进行类的动态修改和增强,生成代理类以便进行调试和分析。 这段代码是通过 Arthas 工具反编译得到的结果。它是一个代理类,位于 `com.sun.proxy` 包下,命名为 `$Proxy0`。该类继承自 `Proxy` 类,并实现了 `MyService` 接口。在 `doSomething` 方法中,通过 `InvocationHandler` 对象的 `invoke` 方法调用了目标对象的 `doSomething` 方法。在静态代码块中,获取了 `java.lang.Object` 类中的 `equals`、`hashCode` 和 `toString` 方法,以及 `MyService` 接口中的 `doSomething` 方法的 `Method` 对象。
这段代码是由JDK动态代理生成的代理类位于`com.sun.proxy`包下,命名为`$Proxy0`。它继承自`Proxy`类并实现了`MyService`接口,包含了目标接口中的方法实现,同时通过`InvocationHandler`对象委托处理方法调用。在静态代码块中获取了目标接口和`Object`类中的方法,并提供了方法的具体实现。
```java ```java
package com.sun.proxy; package com.sun.proxy;
@ -255,10 +186,9 @@ public final class $Proxy0 extends Proxy implements MyService {
} }
``` ```
### 、与其他组件的关系 ### 、与其他组件的关系
1. **接口实现关系** 1. **接口实现关系**
+ JDK动态代理通常基于接口实现。在使用动态代理时需要传入一个接口类型作为参数代理对象会实现这个接口并且在运行时生成的代理类会实现该接口定义的所有方法。因此与其他组件接口的关系是通过实现这些接口来实现的。 + JDK动态代理通常基于接口实现。在使用动态代理时需要传入一个接口类型作为参数代理对象会实现这个接口并且在运行时生成的代理类会实现该接口定义的所有方法。因此与其他组件接口的关系是通过实现这些接口来实现的。
2. **代理类关系** 2. **代理类关系**
@ -269,7 +199,7 @@ public final class $Proxy0 extends Proxy implements MyService {
+ 在使用JDK动态代理时需要提供一个调用处理器`InvocationHandler`)来处理方法调用。该调用处理器可以是自定义的类,它与其他组件接口或类的关系取决于在其`invoke`方法中对方法调用的处理逻辑。 + 在使用JDK动态代理时需要提供一个调用处理器`InvocationHandler`)来处理方法调用。该调用处理器可以是自定义的类,它与其他组件接口或类的关系取决于在其`invoke`方法中对方法调用的处理逻辑。
### 、常见问题 ### 、常见问题
1. **代理对象的类型限制** 1. **代理对象的类型限制**