# dynamic-proxy
**Repository Path**: wzk9261/dynamic-proxy
## Basic Information
- **Project Name**: dynamic-proxy
- **Description**: 基于 Maven 管理,测试 JDK 和 CGLIB 两种代理对接口或类方法的增强效果。
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-01-08
- **Last Updated**: 2024-06-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 准备工作
## 代理简介
代理,简单来说,就是代替原有操作者,即委托者去处理一件事。在 Java 中代理一般分为两种,静态代理和动态代理,动态代理又分为 JDK 动态代理和 Cglib 动态代理。
## 创建项目
创建一个简单的纯后端的 Maven 项目,在其中引入单元测试和 Cglib 相关依赖。
```xml
junit
junit
4.12
test
cglib
cglib
3.3.0
```
注:本案例基于 JDK 1.8
# 静态代理
实现静态代理需要由显式地创建代理类。与动态代理不同的是,静态代理的 class 文件在编译之后,程序运行之前就已经存在了。
## 接口
首先定义一个公共的 `Subject` 接口,该接口后续需要被委托类 `RealSubject` 和代理类 `ProxySubject` 共同实现。
```java
public interface Subject {
void method();
}
```
## 实现类
定义一个实现类 `RealSubject`,实现 `method` 方法。
```java
public class RealSubject implements Subject {
@Override
public void method() {
System.out.println("real method implement");
}
}
```
## 代理类
定义一个代理类 `ProxySubject`,实现 `Subject` 接口,并使用构造器方法注入 `Subject` 接口。
```java
public class ProxySubject implements Subject {
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void method() {
before();
subject.method();
after();
}
private void before() {
System.out.println("static proxy: before method");
}
private void after() {
System.out.println("static proxy: after method");
}
}
```
构造器注入 `Subject` 接口,便于注入指定的实现类。在实现 `method` 方法时,调用委托者的 `method` 方法:`subject.method()`。before 和 after 方法分别为前置和后置的增强方法。
## 单元测试
为静态代理创建相应的单元测试
```java
public class ProxySubjectTest {
@Test
public void method() {
Subject subject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(subject);
proxySubject.method();
}
}
```
运行该测试方法,在控制台中观察输出。
```java
static proxy: before method
real method implement
static proxy: after method
```
# 动态代理
## 准备工作
### 接口和实现类
定义一个接口及其实现类,实现类会委托动态代理来对其实现的方法进行增强。
```java
public interface MyInterface {
void methodA();
int methodB();
int methodC(int param1, int param2);
}
```
```java
public class MyInterfaceImpl implements MyInterface {
@Override
public void methodA() {
System.out.println("method A");
}
@Override
public int methodB() {
System.out.println("method B");
return 0;
}
@Override
public int methodC(int param1, int param2) {
System.out.println("method C");
return param1 + param2;
}
}
```
### 没有实现接口的类
定义一个没有实现接口的类。
```java
public class MyClass {
public void methodA() {
System.out.println("method A");
}
public int methodB() {
System.out.println("method B");
return 0;
}
public int methodC(int param1, int param2) {
System.out.println("method C");
return param1 + param2;
}
}
```
## JDK 动态代理
JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 `InvocationHandler` 的 `invoke` 方法来处理。
### 实现
```java
public class MyInvocationHandler implements InvocationHandler {
private Object delegate;
public MyInvocationHandler(Object delegate) {
this.delegate = delegate;
}
public Object createJDKProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(delegate, args);
after();
return result;
}
private void before() {
System.out.println("jdk proxy: before method");
}
private void after() {
System.out.println("jdk proxy: after method");
}
```
类似于静态代理,JDK 动态代理也是通过构造器注入委托类对象 `delegate`。
#### 创建动态代理对象
在 `createJDKProxy` 方法中,调用 `Proxy` 的 `newProxyInstance` 方法来创建一个 JDK 动态代理对象。
首先阅读 `newProxyInstance` 方法的源码注释:
```java
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
*/
```
可知,`newProxyInstance` 的参数分别应该传入
- 代理类的类加载器。在本案例中,代理类即自定义的 `InvocationHandler` 接口实现类 `MyInvocationHandler`,所以传参为当前类对象的类加载器即可:`this.getClass().getClassLoader()`。
- 代理类要实现的接口数组类对象。这里传入委托类对象实现的接口类对象数组即可:`delegate.getClass().getInterfaces()`。
- 分发方法调用的 invocation handler。这里传入当前代理对象即可:`this`
- 返回值为一个 JDK 代理实例。
#### 重写 invoke 方法
`invoke` 方法基于反射原理,当调用代理者中的接口方法时,会首先进入`invoke`方法中,从 `Object result = method.invoke(delegate, args)` 可以看出,JDK 动态代理基于反射原理调用委托者实现的接口方法,并获取其返回值。并按顺序执行前置和后置增强方法 `before` 和 `after`。
### 单元测试
为 JDK 动态代理创建单元测试
```java
public class JDKProxyTest {
private MyInterface myInterfaceJDKProxy;
@Before
public void setUp() {
MyInterface myInterface = new MyInterfaceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(myInterface);
myInterfaceJDKProxy = (MyInterface) myInvocationHandler.createJDKProxy();
}
@Test
public void methodA() {
myInterfaceJDKProxy.methodA();
}
@Test
public void methodB() {
assertEquals(0, myInterfaceJDKProxy.methodB());
}
@Test
public void methodC() {
int param1 = 2;
int param2 = 3;
assertEquals(param1 + param2, myInterfaceJDKProxy.methodC(param1, param2));
}
}
```
在控制台中观察输出结果
- `methodA`
```java
jdk proxy: before method
method A
jdk proxy: after method
```
- `methodB`
```java
jdk proxy: before method
method B
jdk proxy: after method
```
- `methodC`
```java
jdk proxy: before method
method C
jdk proxy: after method
```
## Cglib 动态代理
Cglib 是一种动态代理方式,底层通过 ASM 产生字节码来完成动态代理,Cglib 与 JDK 动态代理相比,除了可以代理实现接口的类也可以代理非实现接口的类,通过 `FastClass` 类来避免了反射的使用。对 JDK 7 以前的版本来说,JDK 8 动态代理执行效率明显要比 Cglib 动态代理类效率差,JDK 8 即以后版本对 JDK 动态代理进行了相应的优化,这种差距就不那么明显了。但是要代理不实现接口的类来说,Cglib 就是一种必要选择。
### 实现方式一:实现 `MethodInterceptor` 接口
```java
public class MyMethodInterceptor implements MethodInterceptor {
private Object delegate;
public MyMethodInterceptor(Object delegate) {
this.delegate = delegate;
}
public Object createCglibProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(delegate.getClass());
enhancer.setInterfaces(delegate.getClass().getInterfaces());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
before();
Object result = method.invoke(delegate, args);
after();
return result;
}
private void before() {
System.out.println("cglib proxy: before method");
}
private void after() {
System.out.println("cglib proxy: after method");
}
}
```
首先阅读一下 `setSuperclass` 方法的源码
```java
/**
* Set the class which the generated class will extend. As a convenience,
* if the supplied superclass is actually an interface, setInterfaces
* will be called with the appropriate argument instead.
* A non-interface argument must not be declared as final, and must have an
* accessible constructor.
* @param superclass class to extend or interface to implement
* @see #setInterfaces(Class[])
*/
public void setSuperclass(Class superclass) {
if (superclass != null && superclass.isInterface()) {
setInterfaces(new Class[]{ superclass });
} else if (superclass != null && superclass.equals(Object.class)) {
// affects choice of ClassLoader
this.superclass = null;
} else {
this.superclass = superclass;
}
}
```
这里传入的参数 `superClass` 将会被生成的代理类继承,所以这里的 `superClass` 传入委托者(实现类)对应的 Class 对象。
再阅读一下 `setInterfaces` 的源码
```java
/**
* Set the interfaces to implement. The Factory
interface will
* always be implemented regardless of what is specified here.
* @param interfaces array of interfaces to implement, or null
* @see Factory
*/
public void setInterfaces(Class[] interfaces) {
this.interfaces = interfaces;
}
```
所以 `interfaces` 参数传入委托者实现的接口数组即可。这里不设置 `interfaces` 也没有关系,因为即使 `superClass` 参数为接口类型的话,在 `setSuperclass` 方法中会进行 `setInterfaces` 的工作。
`callback` 是 `Enhancer` 中能够拦截原方法并进行增强的关键,`MethodInterceptor` 接口是 `callback` 的子接口之一,可以对委托者的非 final 方法进行拦截,所以 `callback` 设置为当前 `MethodInterceptor` 的实现类对象,即 `this`;如果没有显式地创建 `MethodInterceptor` 的实现类,也可以隐式地创建 `MethodInterceptor` 的匿名内部类:
```java
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
before();
Object result = method.invoke(delegate, args);
after();
return result;
}
});
```
在设置好 `superclass`、`interfaces`、`callback`后,调用 `enhancer.create()` 即可获取 Cglib 动态代理对象。
#### 单元测试
委托者没有实现接口的类的测试
```java
public class CglibProxy4ClassTest {
private MyClass myClass;
@Before
public void setUp() {
MyClass myInterfaceImpl = new MyClass();
MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor(myInterfaceImpl);
myClass = (MyClass) myMethodInterceptor.createCglibProxy();
}
@Test
public void methodA() {
myClass.methodA();
}
@Test
public void methodB() {
assertEquals(0, myClass.methodB());
}
@Test
public void methodC() {
int param1 = 2;
int param2 = 3;
assertEquals(param1 + param2, myClass.methodC(param1, param2));
}
}
```
委托者为实现了接口的类的测试
```java
public class CglibProxy4InterfaceTest {
private MyInterface myInterfaceCglibProxy;
@Before
public void setUp() {
MyInterface myInterface = new MyInterfaceImpl();
MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor(myInterface);
myInterfaceCglibProxy = (MyInterface) myMethodInterceptor.createCglibProxy();
}
@Test
public void methodA() {
myInterfaceCglibProxy.methodA();
}
@Test
public void methodB() {
assertEquals(0, myInterfaceCglibProxy.methodB());
}
@Test
public void methodC() {
int param1 = 2;
int param2 = 3;
assertEquals(param1 + param2, myInterfaceCglibProxy.methodC(param1, param2));
}
}
```
上述两个测试类的测试结果均为:
- `methodA`
```java
cglib proxy: before method
method A
cglib proxy: after method
```
- `methodB`
```java
cglib proxy: before method
method B
cglib proxy: after method
```
- `methodC`
```java
cglib proxy: before method
method C
cglib proxy: after method
```
### 实现方式二:匿名内部类
方式二和方式一的原理是一样的,只是从形式上更简洁,因为使用了匿名内部类。
```java
public class CglibProxyFactory {
public static Object createProxy(final Object delegate) {
return Enhancer.create(delegate.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws InvocationTargetException, IllegalAccessException {
before();
Object result = method.invoke(delegate, args);
after();
return result;
}
private void before() {
System.out.println("inner cglib proxy: before method");
}
private void after() {
System.out.println("inner cglib proxy: after method");
}
});
}
}
```
`createProxy` 方法中直接调用了 `Enhancer` 的 `create` 方法,其源码如下:
```java
/**
* Helper method to create an intercepted object.
* For finer control over the generated instance, use a new instance of Enhancer
* instead of this static method.
* @param type class to extend or interface to implement
* @param callback the callback to use for all methods
*/
public static Object create(Class type, Callback callback) {
Enhancer e = new Enhancer();
e.setSuperclass(type);
e.setCallback(callback);
return e.create();
}
```
- `type` 参数传入的是代理对象将要继承的类或实现的接口,在本案例中即指代`MyClass`、`MyInterfaceImpl` 或 `MyInterface`,这里传参为 `delegate.getClass()`。
- `callback` 参数为所有非 final 方法对应的回调函数,即 `MethodInterceptor` 的实现类或其匿名内部类。这里简化为匿名内部类:
```java
new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws InvocationTargetException, IllegalAccessException {
before();
Object result = method.invoke(delegate, args);
after();
return result;
}
private void before() {
System.out.println("inner cglib proxy: before method");
}
private void after() {
System.out.println("inner cglib proxy: after method");
}
}
```
#### 单元测试
同方式一的单元测试,创建一个 `CglibProxyFactory4ClassTest` 和 `CglibProxyFactory4InterfaceTest`,分别对没有实现接口的类和实现了接口的类做单元测试,测试结果也是断言通过,并且能够完成前置和后置方法中的打印。