公共类
先放一些公共类:
package common.ServiceImpl;
import common.Hello;
import common.HelloService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class HelloServiceImpl implements HelloService {
@Override
public String hello(Hello hello) {
log.info("HelloServiceImpl2收到: {}.", hello.getMessage());
String result = "Hello description is " + hello.getDescription();
log.info("HelloServiceImpl2返回: {}.", result);
return result;
}
}
package common;
public interface HelloService {
String hello(Hello hello);
}
package common;
import lombok.*;
import java.io.Serializable;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
@ToString
public class Hello implements Serializable {
private String message;
private String description;
}
不用动态代理 demo1
下面最简陋的远程调用,客户端进行方法调用,然后服务端接收后本地调用并将结果返回。
package demo1;
import common.Hello;
import common.HelloService;
import common.ServiceImpl.HelloServiceImpl;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static boolean running = true;
public static void main(String[] args) throws IOException, ClassNotFoundException {
ServerSocket serverSocket = new ServerSocket(9999);
while (running){
Socket s = serverSocket.accept();
process(s);
s.close();
}
serverSocket.close();
}
public static void process(Socket s) throws IOException, ClassNotFoundException {
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
ObjectInputStream ois = new ObjectInputStream(is);
DataOutputStream dos = new DataOutputStream(os);
Hello hello = (Hello) ois.readObject();
HelloService service = new HelloServiceImpl();
dos.writeUTF(service.hello(hello));
dos.flush();
}
}
package demo1;
import common.Hello;
import java.io.*;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Hello hello = new Hello("111", "233");
String describ = new Stub().hello(hello);
System.out.println(describ);
}
}
package demo1;
import common.Hello;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class Stub {
public String hello(Hello hello) throws IOException {
Socket s = new Socket("127.0.0.1",9999);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(hello);
s.getOutputStream().write(bao.toByteArray());
s.getOutputStream().flush();
DataInputStream dis = new DataInputStream(s.getInputStream());
String describ = dis.readUTF();
System.out.print(describ);
s.close();
dis.close();
return describ;
}
}
可以看到很多地方都是写死的,并且对于客户端来说应该是调用 HelloServiceImpl 类中的 hello 方法才是真正的远程调用。
下一步优化目标:
- 使用动态代理实现 Stub 的远程调用,返回代理生成的 HelloServiceImpl 类
- 从写 InvocationHandler 方法,将现在 Stub 类中的 hello 方法重构到 invoke 方法中
加入动态代理的 demo1
package demo2;
import common.HelloService;
import common.ServiceImpl.HelloServiceImpl;
import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class Server2 {
public static boolean running = true;
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(9999);
while (running){
Socket s = serverSocket.accept();
process(s);
s.close();
}
serverSocket.close();
}
public static void process(Socket s) throws Exception {
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
ObjectInputStream ois = new ObjectInputStream(is);
DataOutputStream dos = new DataOutputStream(os);
String methodName = ois.readUTF();
Class[] params = (Class[]) ois.readObject();
Object[] args = (Object[]) ois.readObject();
HelloService service = new HelloServiceImpl();
Method m = HelloService.class.getMethod(methodName, params);
String description = (String) m.invoke(service, args);
dos.writeUTF(description);
dos.flush();
dos.close();
}
}
package demo2;
import common.Hello;
import common.HelloService;
public class Client2 {
public static void main(String[] args) {
HelloService service = Stub2.getStub();
String description = service.hello(new Hello("111","233"));
System.out.print(description);
}
}
package demo2;
import common.HelloService;
import java.io.DataInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class Stub2 {
public static HelloService getStub(){
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket("127.0.0.1",9999);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
String methodName = method.getName();
Class[] params = method.getParameterTypes();
oos.writeUTF(methodName);
oos.writeObject(params);
oos.writeObject(args);
oos.flush();
DataInputStream dis = new DataInputStream(s.getInputStream());
String description = dis.readUTF();
s.close();
oos.close();
return description;
}
};
Object o = Proxy.newProxyInstance(HelloService.class.getClassLoader(), new Class[]{HelloService.class}, h);
return (HelloService) o;
}
}
使用动态代理后明显比不使用耦合性更低,但是仍然有许多问题需要优化。 下一步优化目标:
1.将请求规范化(现在如果有两个类有同样的方法就会出现问题)
|