远程调用-1
一、远程调用
考试时不会,求救室友
自己有个方法不会实现,但是别人会实现,让别做的过程,就是远程调用
1.1好处
社会的分工
二、实现调用
Socket IO 流 反射
2.1 实现流程
2.2 室友的实现
ServerSocket
/**
* 室友的实现
* @author CodeLab
*1 室友打开手机+ 监听短信
*2 室友收到题目
*3 室友解析题目
*4 室友做答案
*5 室友做出来了,把答案发给你
*/
public class ClassmateApp {
public static void main(String[] args) throws Exception {
//1室友打开手机+ 监听短信
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("手机打开了,开始等待。。。");
Socket socket = serverSocket.accept(); // 开始监听
System.out.println("菜逼的题目来了");
System.out.println("获取它的题目");
InputStream inputStream = socket.getInputStream();
ObjectInputStream objectInputStream = new
ObjectInputStream(inputStream);
String question = (String)objectInputStream.readObject();
// 1 + 1
System.out.println("接受到菜逼的题目为"+question);
Integer result = 1 + 1 ; // 室友算出来
System.out.println("答案算出来了");
System.out.println("发送答案");
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new
ObjectOutputStream(outputStream);
objectOutputStream.writeObject(result);
System.out.println("答案发送成功");
// 关闭资源
close(objectOutputStream,outputStream,objectInputStream,inputStream,socket,
serverSocket);
}
/**
* 以后关闭流时,使用下面的操作
* 所有的流都实现了Closeable 接口
* @param claseables
*/
public static void close(Closeable ...claseables) {
for (Closeable closeable : claseables) {
if(null!=closeable) {
try {
closeable.close(); // 关闭时也可能发生异常
} catch (IOException e) {
e.printStackTrace();
}finally {
closeable = null ; // 但对象失去引用时,gc 会回收它
}
}
}
}
}
2.2 自己的实现
Sokcet
/**
* 自己考试的实现
* @author CodeLab
*1 读题目,发现不会
*2 室友会这个题目
*3 把题目发生给室友
*4 接收室友的答案
*5 把答案抄上去
*/
public class SlefApp {
public static void main(String[] args) throws UnknownHostException,
IOException, ClassNotFoundException {
System.out.println("1 开始考试");
String question = "1 + 1 =?";
System.out.println("这个题目"+question+",不会,求救室友");
System.out.println("把题目发给室友");
Socket socket = new Socket("localhost", 8888);
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new
ObjectOutputStream(outputStream);
objectOutputStream.writeObject(question);
System.out.println("题目发送完毕");
// 接收室友的答案
InputStream inputStream = socket.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
Object answer = objectInputStream.readObject();
System.out.println("室友的答案接收完毕");
System.out.println("我写上去:1 +1 = "+answer);
close(objectInputStream,inputStream,objectOutputStream,
outputStream,socket);
}
/**
* 以后关闭流时,使用下面的操作
* 所有的流都实现了Closeable 接口
* @param claseables
*/
public static void close(Closeable ...claseables) {
for (Closeable closeable : claseables) {
if(null!=closeable) {
try {
closeable.close(); // 关闭时也可能发生异常
} catch (IOException e) {
e.printStackTrace();
}finally {
closeable = null ; // 但对象失去引用时,gc 会回收它
}
}
}
}
}
三、远程调用建模
3.1 我
服务的消费者
3.2 室友
服务的提供者,提供算出来1+1 = ? 答案
3.3 调用的内容->某种服务
1 +1 = ? 调用一个接口里面的方法
3.4 题目
3.5 答案
四、实现该模型
4.1 创建api 项目
Api 里面非常简单,只有一个接口
/**
* 提供加法运算的接口
* @author CodeLab
*
*/
public interface AddService {
/**
* 加法运行
* @param a
* @param b
* @return
*/
Integer add(Integer a,Integer b);
Integer desc(Integer a,Integer b);
}
4.2 服务的消费者
Maven 项目
4.2.1 服务提供者实现api
在pom.xml 文件里面依赖
<dependencies>
<dependency>
<groupId>com.sxt</groupId>
<artifactId>api</artifactId>
<version>6.0</version>
</dependency>
</dependencies>
实现接口
public class AddServiceImpl implements AddService{
/**
* 我作为服务的提供者,我知道他怎么做
*/
@Override
public Integer add(Integer a, Integer b) {
return a + b;
}
@Override
public Integer desc(Integer a, Integer b) {
return a - b ;
}
}
4.2.2 服务提供者监听端口
public class ClassMateApp {
public static void main(String[] args) {
ServerSocket serverSocket = null ;
try {
serverSocket = new ServerSocket(8888);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
start(serverSocket);
}
}
public static void start(ServerSocket serverSocket) {
// 使用监听
try {
System.out.println("开始监听菜逼的题目");
Socket socket = serverSocket.accept();
// 获取菜逼的题目
InputStream in = socket.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(in);
Request request = (Request)objectInputStream.readObject();
// 反射调用得到题目的答案
Response answer = getAnswer(request);
// 将答案发给菜逼
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new
ObjectOutputStream(outputStream);
objectOutputStream.writeObject(answer);
// 关闭资源的操作
closes(objectOutputStream,outputStream,objectInputStream,in,socket);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void closes(Closeable ...closeables) {
for (Closeable closeable : closeables) {
if(null!=closeable) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
closeable = null ;
}
}
}
}
private static Response getAnswer(Request request)
throws ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
// 题目获取完毕
String interfaceName = request.getInterfaceName();
String methodName = request.getMethodName();
Object[] args2 = request.getArgs();
Class<?> interfcs = Class.forName(interfaceName); // 获取到接口了
// 获取该接口的实现类对象
Object objectImpl = getImplClass(interfcs);
Class<?>[] parameterTypes = new Class<?>[args2.length];
for (int i = 0; i < parameterTypes.length; i++) {
parameterTypes[i] = args2[i].getClass(); // 获取参数的类型
}
Method method = objectImpl.getClass().getMethod(methodName, parameterTypes);
Object result = method.invoke(objectImpl, args2); // 将答案算出来
Response response = new Response();
response.setResult(result);// 包装答案
return response ;
}
private static Object getImplClass(Class<?> interfcs) {
// AddService -》 AddServiceImpl
// 通过接口获取它的实现类对象
return new AddServiceImpl();
}
}
4.3 服务的消费者
4.3.1 服务消费者消费该接口
Pom.xml依赖
<dependencies>
<dependency>
<groupId>com.sxt</groupId>
<artifactId>api</artifactId>
<version>6.0</version>
</dependency>
</dependencies>
调用:
public class SelfConsumer {
public static void main(String[] args) {
System.out.println("我在考试");
System.out.println("有个题目 : 1 + 1= ? 不会");
System.out.println("求救室友");
AddService addServiceProxy =
(AddService)ProxyObjectFactory.createProxy(AddService.class);
// 这里的接口需要运行,需要一个代理对象
/**
* 代理对象执行方法,进invoke 里面
*/
Integer result = addServiceProxy.add(4, 6);
// 体现我在调用这个接口,服务的消费者
System.out.println("答案已经获取到了"+result);
Integer desc = addServiceProxy.desc(5, 1);
System.out.println("答案已经获取到了"+desc);
}
}
4.3.2 代理对象的调用细节
/**
* 给接口创建一个代理对象
* @author CodeLab
*
*/
public class ProxyObjectFactory {
/**
* 给一个接口提供代理对象
* @param clazz
* 接口
* @return
* 代理对象
*/
public static Object createProxy(Class<?> clazz) {
return
Proxy.newProxyInstance(ProxyObjectFactory.class.getClassLoader(),
new Class<?>[] {
clazz}, new InvocationHandler() {
// 以后代理对象执行任何方法,都有进入
public Object invoke(Object proxy, Method method, Object[]
args) throws Throwable {
// 若在这里面实现了远程调用室友,则调用就可以完成
// TODO 如何在此实现对室友的调用
// 要调用我,必须告诉我你要调用那个对象(对象的名称即
可),你要调用这个对象里面的那个方法(方法的名称),还有这个方法的参数(args)
//clazz.getName() : 接口名称
Response reps = rpc(new Request(clazz.getName(),
method.getName(), args));
return reps.getResult();
}
});
}
/**
* 向使用发生一个request 对象,得到使用的响应
* @param request
* request
* @return
* response
* 得到室友的响应
*/
public static Response rpc(Request request) {
Response response = null ;
try {
Socket socket = new Socket("localhost", 8888);
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(request);// 给室友把题目发送过去
// 接收室友的答案
InputStream inputStream = socket.getInputStream();
ObjectInputStream objectInputStream =
new ObjectInputStream(inputStream);
response = (Response)objectInputStream.readObject();
closes(objectInputStream,inputStream,objectOutputStream,
outputStream,socket);
} catch (Exception e) {
e.printStackTrace();
}
return response;
}
public static void closes(Closeable ...closeables) {
for (Closeable closeable : closeables) {
if(null!=closeable) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
closeable = null ;
}
}
}
}
}
五、引入负载均衡的概念
从一个列表里面选一个出来的过程
5.1 高并发
一个使用慢不过来,又请了一个室友
调用太多,一个人忙不过来
如何在3 个室友里面选一个出来
5.2 服务端的负载均衡
类似nginx 的模式,由服务决定访问那个地址
5.3 客户端的负载均衡
5.4 使用客户端的负载均衡来调用不同的室友
{
Localhost:8888
Localhost:7777
Localhost:9999
}
5.5 注册中心的引入
5.6 室友的启动后需要注册自己
5.7 我调用时,需要从注册中心拉取服务的列表
5.8 注册中心该怎么做?
Map
{
K: 服务名称,
V:服务的地址
}
Zookeeper 是最通用的注册中心
还没有评论,来说两句吧...