1. 什么是动态代理
在运行时为指定的接口自动生成代理对象,并通过 invoke 方法增强了这些对象的功能
2. 两个核心组件
java.lang.reflect.Proxy
类
这个类提供了方法:newProxyInstance()
用来创建一个代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
......
}
参数说明:
1. loader
:用于加载代理类的类加载器;通常传入被代理类的类加载器
2. interfaces
: 被代理类实现的一些接口,数组形式;
3. h
: 实现了 InvocationHandler
接口的对象;
疑惑解释:
【Q】为什么Loader是用于加载代理类的类加载器,但又传入的是被代理类的类加载器?
【A】由于动态代理类需要实现与被代理类相同的接口,那么就要代理类必须具有和被代理类完全相同的接口定义,要实现这一点需要代理类使用和被代理类相同的类加载器
java.lang.reflect.InvocationHandler
接口(提供了invoke方法)
public interface InvocationHandler {
/**
* 当你使用代理对象调用方法的时候实际会调用到这个方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
参数说明:
1. proxy
:动态生成的代理类
2. method
: 与代理类对象调用的方法相对应
3. args
: 当前 method 方法的参数
3. 使用示例(以简单的RPC 过程为例)
定义代理类ClientProxy
说明
- 在
getProxy
方法中,InvocationHandler h
位置(第 3 个入口参数)处,要传实现了InvocationHandler
接口的类。由于ClientProxy
类实现了这个接口,所以这里在调用newProxyInstance
直接传入了this
- 在
invoke
方法中,没有像别的动态代理示例那样,在其中调用method.invoke(target, args);
。因为这里的场景是:在RPC过程中,客户端对输入参数的封装,然后发送给服务端,服务端来执行相应的方法(客户端只有接口定义,而没有接口实现,所以这里并不需要method.invoke(target, args)
)(但是在服务端中,会调用method.invoke(target, args)
)
package com.chanlee.crpc.v1.client;
import com.chanlee.crpc.v1.common.RpcRequest;
import com.chanlee.crpc.v1.common.RpcResponse;
import lombok.AllArgsConstructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import static com.chanlee.crpc.v1.client.IOClient.sendRequest;
@AllArgsConstructor
public class ClientProxy implements InvocationHandler {
/**
* 服务端 IP
*/
private String host;
/**
* 服务端端口号
*/
private int port;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//构建request请求
RpcRequest request = RpcRequest.builder()
.interfaceName(method.getDeclaringClass().getName())
.method(method.getName())
.paramsTypes(method.getParameterTypes())
.params(args)
.build();
//发送请求并获取响应
RpcResponse<Object> response = sendRequest(host, port, request);
//返回结果数据
return response.getData();
}
public <T> T getProxy(Class<T> tClass){
Object o = Proxy.newProxyInstance(
tClass.getClassLoader(),
new Class[]{tClass},
this
);
return (T)o;
}
}
客户端代码(使用上面的代理类)
说明:
- 下方代码没有出现
Proxy.newProxyInstance(...)
是因为ClientProxy
类中的getProxy(...)
已经封装了该方法 - 当代理类调用对应的方法时,会被
invoke()
方法截取,然后执行invoke()
方法中的代码逻辑
package com.chanlee.crpc.v1.client;
import com.chanlee.crpc.v1.common.User;
import com.chanlee.crpc.v1.service.UserService;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
/**
* 客户端代码
*/
public class Client{
public static void main(String[] args){
ClientProxy clientProxy = new ClientProxy("127.0.0.1", 8003);
UserService proxy = clientProxy.getProxy(UserService.class);
//调用方法 1
User user = proxy.getUserById(1);
System.out.println(user);
//调用方法 2
User codingBoy = User.builder()
.age(25)
.id(32)
.realName("coding boy")
.build();
Integer i = proxy.insertUser(codingBoy);
System.out.println(i);
}
}