先贴一段看到的对动态代理的比较不错的解释
动态代理其实就是Java.lang.reflect.Proxy类动态的根据指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有指定的接口(在参数中传入的接口数组),也就是说,返回的对象可以转换类型为接口数组中的任何一个接口类型。然后再利用第一个参数的classloader将class byte加载进系统,最后生成这样一个类的对象并初始化该对象的一些值,如invocationHandler,则是在参数中传入的第三个参数,以及所有的接口对应的method成员,初始化之后将对象返回给调用的客户端,这样客户端就拿到了一个实现所有接口的Proxy对象
还有一部分很关键,就是动态代理会代理哪些方法:
在Proxy.newProxyInstance方法调用时,具体步骤如下
1 根据传入的第二个参数interface数组动态生成类,实现interfaces数组中每个interface的接口方法,并且继承了Proxy类,重写了hashcode,toString,equals等方法,对应的类名称为$Proxy0,这里有一个很重要的点,就是会重写哪些方法,上面已经介绍了包括所有interfacade的接口方法,重写了3个基本Object的方法,所以例如getClass等方法是不会被重写的,可以通过对比动态代理的返回的对象调用toString和getClass方法来测试,前者是会经过代理方法,而后者却不会经过代理方式。
2 通过传入的第一个参数classloader将第一步生成的类加载到jvm中
3 利用第三个参数,调用$Proxy0的$Proxy0(InvocationHandler)构造方法,创建这个类的实例,并且将invocationHandler对象设置进类实例中,循环所有接口方法,将invocationHandler对象织入实现中,所以调用任何一个接口方法,实际上都是调用的invocationHandler.invoke方法,真正的业务逻辑实际也在invoke里面,通过传入的具体的invocationHandler对象来实现(一般是新建类继承InvocationHandler类,并且将真正的实现者注入进去),至于$Proxy0会不会在invoke方法的前后加入代码,例如日志,统计等没有具体研究。另外还会生成Method对象,初始化$Proxy0实例的几个Method成员变量
4 将第三部生成的$Proxy0实例返回给客户端。
再来贴出通过动态代理的实现的RPC调用的代码,从这个例子学到了很多东西,包括动态代理,以及基于Java动态代理的RPC调用的基础原理,当然这个例子只是用Java实现
的RPC框架调用。
1 基础RPC框架类,包括暴露服务和引用服务
package whu;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Locale.Category;
public class RpcFramework {
public static void export(Object service, Class interfaceClazz, int port) throws Exception {
if (service == null) {
throw new IllegalAccessException("service instance == null");
}
if (port < 0 || port > 65535) {
throw new IllegalAccessException("Invalid port " + port);
}
System.out.println("Export service " + service.getClass().getName() + " on port " + port);
ServerSocket server = new ServerSocket(port);
for (;;) {
final Socket socket = server.accept();
try {
new Thread(new Runnable() {
@Override
public void run() {
try {
try {
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
try {
String interfaceName = input.readUTF();
String methodName = input.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
Object[] arguments = (Object[]) input.readObject();
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
try {
if (!interfaceName.equals(interfaceClazz.getName())) {
throw new IllegalAccessException("Interface wrong, export:" + interfaceClazz
+ " refer:" + interfaceName);
}
Method method = service.getClass().getMethod(methodName, parameterTypes);
Object result = method.invoke(service, arguments);
output.writeObject(result);
} catch (Throwable t) {
output.writeObject(t);
} finally {
output.close();
}
} finally {
input.close();
}
} finally {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("unchecked")
public static <T> T refer(Class<T> interfaceClass, String host, int port) throws Exception {
if (interfaceClass == null) {
throw new IllegalAccessException("Interface class == null");
}
if (!interfaceClass.isInterface()) {
throw new IllegalAccessException(interfaceClass.getName() + " must be interface");
}
if (host == null || host.length() == 0) {
throw new IllegalAccessException("host == null");
}
if (port <= 0 || port > 65535) {
throw new IllegalAccessException("Invalid port " + port);
}
System.out.println("Get remote service " + interfaceClass.getName() + " from server " + host + ":" + port);
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] { interfaceClass },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Socket socket = new Socket(host, port);
try {
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
try {
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(args);
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
try {
Object result = input.readObject();
if (result instanceof Throwable) {
throw (Throwable) result;
}
return result;
} finally {
input.close();
}
} finally {
output.close();
}
} finally {
socket.close();
}
}
});
}
}
2 接口类
package whu;
public interface HelloService {
String hello();
String hello(String name);
}
3 接口实现类
package impl;
import whu.HelloService;
public class HelloServiceImpl implements HelloService {
@Override
public String hello() {
return "Hello";
}
@Override
public String hello(String name) {
return "Hello," + name;
}
}
4 服务提供方+Server
package whu;
import impl.HelloServiceImpl;
public class RpcProvider {
public static void main(String[] args) throws Exception {
HelloService service = new HelloServiceImpl();
RpcFramework.export(service, HelloService.class, 9000);
}
}
package whu;
public class RpcConsumer {
public static void main(String[] args) throws Exception {
HelloService service = RpcFramework.refer(HelloService.class, "127.0.0.1", 9000);
String result = service.hello("rod");
System.out.println(result);
}
}