版本V1.0:基于socket通信的rpc

项目截图:
这里写图片描述

服务器端:
1 首先自定义一个注解。
2 Spring启动时, 构造一个线程用于与客户端进行通信。
3 使用自定义注解,实现业务处理类
4 启动Spring, 开启服务器端

1 自定义注解:

package com.xxz.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Component;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface SocketRpc {
    Class<?> value();
}

2 启动Spring构造一个线程用于通信:

package com.xxz.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.xxz.annotation.SocketRpc;
import com.xxz.bean.TranportBean;

public class ServerSocketHandler implements ApplicationContextAware, InitializingBean{

    private String host;
    private int port;

    private Map<String, Object> hashMap = new HashMap<String, Object>();

    public ServerSocketHandler(String host){
        this.host = host;
    }

    public void setApplicationContext(ApplicationContext ctx)throws BeansException {
        // 获取所有的socketrpc注解的bean
        Map<String, Object> beansWithAnnotation = ctx.getBeansWithAnnotation(SocketRpc.class);
        if(MapUtils.isNotEmpty(beansWithAnnotation)){
            for(Object serviceBean : beansWithAnnotation.values()){
                String interfaceName = serviceBean.getClass().getAnnotation(SocketRpc.class).value().getName();
                hashMap.put(interfaceName, serviceBean);
            }
        }
    }

    public void afterPropertiesSet() throws Exception {
        // 在这里开启服务端
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket(8080);
            System.out.println("the time server is started in port : " + 8080);
            while(true){
                socket = serverSocket.accept();
                // 主线程接受客户连接请求, 不做业务逻辑处理, 需要开启一个新线程实现业务逻辑处理, 新线程处理完逻辑后,就退出
                new Thread(new HandlerBizThread(socket)).start();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    class HandlerBizThread implements Runnable{

        private Socket socket;

        public HandlerBizThread(Socket socket){
            this.socket = socket;
        }

        public void run() {
            ObjectInputStream ois = null;
            PrintWriter out = null;
            try{
                ois = new ObjectInputStream(socket.getInputStream());
                TranportBean readObject = (TranportBean)ois.readObject();

                // 服务器端  收到类名 方法名 参数 参数类型, 调用服务器端业务实现类执行
                // 根据类名, 从hashmap中得出具体的实现类
                Object serviceBean = hashMap.get(readObject.getClassName());
                String className = readObject.getClassName();
                String methodName = readObject.getFunctionName();
                Class<?> [] paramType = readObject.getParamType();
                Object [] args = readObject.getArgsParam();

                Class<?> forName = Class.forName( className);

                Method method = forName.getMethod(methodName, paramType);
                Object resp = method.invoke(serviceBean, args);

                out = new PrintWriter(socket.getOutputStream(), true);
                // 返回结果写到socket中, 给客户端
                out.println(resp);

            }catch(Exception e){
                e.printStackTrace();
            }

        }

    }

    /*
    class HandlerThread implements Runnable{

        private Socket socket = null;

        public HandlerThread(Socket socket){
            this.socket= socket;

        }
        //使用socket来进行通信
        public void run() {
            BufferedReader in = null;
            PrintWriter out = null;
            try{
                in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
                out = new PrintWriter(this.socket.getOutputStream(), true);
                String currentTime = null;
                String body = null;
                while(true){
                    body = in.readLine();
                    if(body == null) // bufferedReader当读到最后一个字符时, 返回null
                        break;
                    System.out.println("the time server received order : " + body);
                    currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
                    out.println(currentTime);
                }

            }catch(IOException e){
                e.printStackTrace();
                //出异常时, 关闭socket流
                if(socket != null){
                    try {
                        socket.close();
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }

                if(in != null){
                    try {
                        in.close();
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }

                if(out != null){
                    out.close();
                }
            }

        }

    }*/

}

3 使用自定义注解, 实现业务处理:

package com.xxz.service.impl;

import com.xxz.annotation.SocketRpc;
import com.xxz.reflectInterfaceTest.BizService;

@SocketRpc(BizService.class)
public class BizServiceImpl implements BizService {

    public String hello(String param) {

        param = (Integer.parseInt(param)*2)+"";
        return param;
    }

}

4 启动Spring:

package com.xxz.service.impl;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class RpcBootstrap {

    @SuppressWarnings("resource")
    public static void main(String[] args) {
        new ClassPathXmlApplicationContext("spring.xml");
    }
}

客户端:
1 构造动态代理对象
2 获取客户端想要调用服务器端的类名, 方法名, 参数类型, 参数args
3 通过socket将类名, 方法名等, 传给服务器端。并且接受服务器端执行接口的返回值。

1 构造动态代理对象:

package com.xxz.proxy;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

import com.xxz.bean.TranportBean;

public class RpcProxy {

    private String host;

    public RpcProxy(String host){
        this.host = host;
    }

    @SuppressWarnings("unchecked")
    public <T> T create(Class<?> interfaceName){
        return (T) Proxy.newProxyInstance(
                interfaceName.getClassLoader(), 
                new Class<?> [] {interfaceName}, 
                new InvocationHandler() {

                    @SuppressWarnings("resource")
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        TranportBean tranportBean = new TranportBean();
                        // 获取调用的类名
                        String className = method.getDeclaringClass().getName();
                        tranportBean.setClassName(className);
                        // 获取调用方法名
                        String functionName = method.getName();
                        tranportBean.setFunctionName(functionName);
                        // 获取调用方法的参数类型
                        Class<?> [] paramType = method.getParameterTypes();
                        tranportBean.setParamType(paramType);
                        // 获取参数
                        Object[] argsParam = args;
                        tranportBean.setArgsParam(argsParam);

                        // 使用socket把该对象传输过去
                        Socket socket = null;
                        BufferedReader in = null;
                        ObjectOutputStream oos = null;
                        try{
                            socket = new Socket("127.0.0.1", 8080);

                            oos= new ObjectOutputStream(socket.getOutputStream());
                            oos.writeObject(tranportBean);
                            socket.shutdownOutput();

                            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                            // 读取服务器端写回的执行结果
                            String resp = in.readLine();
                            return resp;
                        }catch(IOException e){
                            e.printStackTrace();
                        }

                        return null;
                    }
                });
    }
}

2 启动测试类:

package com.xxz.reflectInterfaceClient;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.xxz.proxy.RpcProxy;
import com.xxz.reflectInterfaceTest.BizService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring.xml")
public class HelloServiceTest {

    @Autowired
    private RpcProxy rpcProxy;

    @Test
    public void testHello(){
        BizService bizService = rpcProxy.create(BizService.class);
        String hello = bizService.hello("2");// 调用内部invacationhandler实现类
        System.out.println(hello);
    }



}

源码下载:http://download.csdn.net/download/xiongxianze/10209406

猜你喜欢

转载自blog.csdn.net/xiongxianze/article/details/79082652
今日推荐