一、UML类图和时序图
二、实例说明
代理模式分静态代理和动态代理。静态代理,需要在编译器就确认代理类。而动态代理,则是在运行时新增代理类,扩展性更强。我们主要以动态代理举例说明,这里通过实现一个简单的RPC框架来了解下动态代理。
RPC调用框架
public interface HelloService {
String sayHello(String str);
}
//服务端需要提供的服务
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String str) {
String hello = "say hello : " + str;
System.out.println(hello);
return hello;
}
}
public class SimpleRpcFramework {
private static ExecutorService executorService = Executors.newCachedThreadPool();
// rpc服务端调用
public static Object export(final Object service,int port)throws IOException{
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
Socket socket = serverSocket.accept();
executorService.submit(new Runnable() {
@Override
public void run() {
try {
try {
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
try {
String methodName = in.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) in.readObject();
Object[] arguments = (Object[]) in.readObject();
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
try {
Method method = service.getClass().getMethod(methodName, parameterTypes);
Object result = method.invoke(service, arguments);
out.writeObject(result);
} catch (Throwable t) {
out.writeObject(t);
} finally {
out.close();
}
} finally {
in.close();
}
} finally {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
//rpc客户端调用
public static <T> T refer(Class<T> interfaceClass,String host,int port) throws IOException {
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = new Socket(host,port);
try {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
try {
out.writeUTF(method.getName());
out.writeObject(method.getParameterTypes());
out.writeObject(args);
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
try {
Object result = in.readObject();
if (result instanceof Throwable) {
throw (Throwable) result;
}
return result;
}finally {
in.close();
}
}finally {
out.close();
}
}finally {
socket.close();
}
}
});
}
}
//服务端启动,提供RPC服务
public class RpcServer {
public static void main(String[] args) throws IOException{
HelloService helloService = new HelloServiceImpl();
SimpleRpcFramework.export(helloService, 8089);
}
}
//客户端启动,调用RPC服务
public class RpcClient {
public static void main(String[] args) throws IOException{
try {
HelloService refer = SimpleRpcFramework.refer(HelloService.class, "127.0.0.1", 8089);
for (int i = 0; i < Integer.MAX_VALUE; i++) {
String hello = refer.sayHello("rpc " + i);
System.out.println(hello);
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
三、代理模式使用场景以及注意事项
1、Spring中的AOP切面编程
要求:不修改原来的class类的情况下,在现有业务的基础上添加或者移除日志、事务、权限控制等功能。
2、RPC服务中的客户端调用
RPC调用的核心是动态代理和socket。客户端和服务端约定好通信协议,客户端通过动态代理封装要传递的参数如:接口名称、方法名、参数名等,然后通过socket和服务端进行通信传输。
3、动态代理适用于接口调用,如果没有接口的话,需要通过CGLIB来实现类的动态代理。