Spring+Netty+Protostuff+ZooKeeper实现轻量级RPC服务(二)

释放双眼,带上耳机,听听看~!

接上文【转】Spring+Netty+Protostuff+ZooKeeper实现轻量级RPC服务 (二)

整体文件结构

Spring+Netty+Protostuff+ZooKeeper实现轻量级RPC服务(二) 
其中(Maven 的多模块构建):

  • SpringMVC_RPC_Client
  • SpringMVC_RPC_Common
  • SpringMVC_RPC_Server
  • SpringMVC_RPC_Service 服务接口工程
  • SpringMVC_RPC_Service_Impl

服务端设计配置

服务接口工程SpringMVC_RPC_Service :

主要定义服务接口类和服务涉及到的实体类

SpringMVC_RPC_Service工程目录结构图

SpringMVC_RPC_Service工程 pom.xml文件:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3    <modelVersion>4.0.0</modelVersion>
4    <parent>
5        <groupId>com.zhihua</groupId>
6        <artifactId>SpringMVC_RPC_Parent</artifactId>
7        <version>0.0.1-SNAPSHOT</version>
8    </parent>
9    <artifactId>SpringMVC_RPC_Service</artifactId>
10    <packaging>jar</packaging>
11    <dependencies>
12        <dependency>
13            <groupId>com.alibaba</groupId>
14            <artifactId>fastjson</artifactId>
15            <version>1.1.41</version>
16        </dependency>
17        <dependency>
18            <groupId>com.zhihua</groupId>
19            <artifactId>SpringMVC_RPC_Common</artifactId>
20            <version>0.0.1-SNAPSHOT</version>
21        </dependency>
22    </dependencies>
23
24</project>
25

SpringMVC_RPC_Service工程服务接口IHelloService


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1package com.zhihua.service;
2
3import java.util.List;
4
5import com.zhihua.entity.User;
6
7public interface IHelloService {
8
9    public String hello(String name);
10
11    public User getUser(String name);
12
13    public List<User> getUsers(int size);
14
15    public User updateUser(User user);
16}
17

SpringMVC_RPC_Service工程User类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1package com.zhihua.entity;
2
3import java.util.Date;
4
5import com.alibaba.fastjson.JSON;
6
7public class User {
8
9    private String name;
10    private Date birthday;
11    private boolean sex;
12    public User(String name,Date birthday,boolean sex){
13        this.name = name;
14        this.birthday = birthday;
15        this.sex = sex;
16    }
17    public String getName() {
18        return name;
19    }
20    public void setName(String name) {
21        this.name = name;
22    }
23    public Date getBirthday() {
24        return birthday;
25    }
26    public void setBirthday(Date birthday) {
27        this.birthday = birthday;
28    }
29    public boolean isSex() {
30        return sex;
31    }
32    public void setSex(boolean sex) {
33        this.sex = sex;
34    }
35
36    public String toString(){
37        return JSON.toJSONString(this);
38    }
39}
40

工程依赖引用的SpringMVC_RPC_Common工程:

主要放置服务端和客户端共用的组件,而且这些组件可以被其他服务包共用,所以要抽取出来

SpringMVC_RPC_Common工程目录结构图

SpringMVC_RPC_Common工程pom.xml文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3    <modelVersion>4.0.0</modelVersion>
4    <parent>
5        <groupId>com.zhihua</groupId>
6        <artifactId>SpringMVC_RPC_Parent</artifactId>
7        <version>0.0.1-SNAPSHOT</version>
8    </parent>
9    <artifactId>SpringMVC_RPC_Common</artifactId>
10    <properties>
11        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12    </properties>
13    <dependencies>
14        <!-- Netty -->
15        <dependency>
16            <groupId>io.netty</groupId>
17            <artifactId>netty-all</artifactId>
18            <version>4.0.24.Final</version>
19        </dependency>
20        <!-- Protostuff -->
21        <dependency>
22            <groupId>com.dyuproject.protostuff</groupId>
23            <artifactId>protostuff-core</artifactId>
24            <version>1.0.8</version>
25        </dependency>
26        <dependency>
27            <groupId>com.dyuproject.protostuff</groupId>
28            <artifactId>protostuff-runtime</artifactId>
29            <version>1.0.8</version>
30        </dependency>
31        <!-- Objenesis -->
32        <dependency>
33            <groupId>org.objenesis</groupId>
34            <artifactId>objenesis</artifactId>
35            <version>2.1</version>
36        </dependency>
37        <!-- Spring -->
38        <dependency>
39            <groupId>org.springframework</groupId>
40            <artifactId>spring-context</artifactId>
41            <version>4.0.1.RELEASE</version>
42        </dependency>
43    </dependencies>
44</project>
45

SpringMVC_RPC_Common工程RpcService注解


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1package com.zhihua.annotation;
2
3import java.lang.annotation.ElementType;
4import java.lang.annotation.Retention;
5import java.lang.annotation.RetentionPolicy;
6import java.lang.annotation.Target;
7
8import org.springframework.stereotype.Component;
9
10@Target({ElementType.TYPE})
11@Retention(RetentionPolicy.RUNTIME)
12@Component // 表明可以被 Spring 扫描
13public @interface RpcService {
14
15    Class<?> value();
16}
17

SpringMVC_RPC_Common工程Constant接口


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1package com.zhihua.common;
2
3/**
4 * Constant接口
5 * <请替换成功能描述> <br>
6 * <请替换成详细描述>
7 * @author caizh
8 * @since [1.0.0]
9 * @version [1.0.0,2017年3月24日]
10 */
11public interface Constant {
12
13    int ZK_SESSION_TIMEOUT = 5000;
14    //在创建数据节点前,先用zkCli.sh客户端连接上服务端,查看目前存在的数据节点,
15    //把下面的/zookeeper/quota改为你自己的,/zookeeper/quota是我自己Zookeeper的节点
16
17    String ZK_REGISTRY_PATH = "/zookeeper_quota";
18    String ZK_DATA_PATH = ZK_REGISTRY_PATH + "/data";
19}
20

SpringMVC_RPC_Common工程RpcDecoder解码类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1package com.zhihua.common;
2
3import java.util.List;
4
5import io.netty.buffer.ByteBuf;
6import io.netty.channel.ChannelHandlerContext;
7import io.netty.handler.codec.ByteToMessageDecoder;
8
9/**
10 * RpcDecoder解码类
11 * <请替换成功能描述> <br>
12 * <请替换成详细描述>
13 * @author caizh
14 * @since [1.0.0]
15 * @version [1.0.0,2017年3月24日]
16 */
17public class RpcDecoder extends ByteToMessageDecoder{
18
19    private Class<?> genericClass;
20
21    public RpcDecoder(Class<?> genericClass) {
22        this.genericClass = genericClass;
23    }
24
25    @Override
26    public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
27        if (in.readableBytes() < 4) {
28            return;
29        }
30        in.markReaderIndex();
31        int dataLength = in.readInt();
32        if (dataLength < 0) {
33            ctx.close();
34        }
35        if (in.readableBytes() < dataLength) {
36            in.resetReaderIndex();
37            return;
38        }
39        byte[] data = new byte[dataLength];
40        in.readBytes(data);
41
42        Object obj = SerializationUtil.deserialize(data, genericClass);
43        out.add(obj);
44    }
45
46}
47

SpringMVC_RPC_Common工程RpcEncoder解码类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1package com.zhihua.common;
2
3import io.netty.buffer.ByteBuf;
4import io.netty.channel.ChannelHandlerContext;
5import io.netty.handler.codec.MessageToByteEncoder;
6
7/**
8 * RpcEncoder编码类
9 * <请替换成功能描述> <br>
10 * <请替换成详细描述>
11 * @author caizh
12 * @since [1.0.0]
13 * @version [1.0.0,2017年3月24日]
14 */
15@SuppressWarnings("rawtypes")
16public class RpcEncoder extends MessageToByteEncoder{
17
18    private Class<?> genericClass;
19
20    public RpcEncoder(Class<?> genericClass) {
21        this.genericClass = genericClass;
22    }
23
24    @Override
25    public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
26        if (genericClass.isInstance(in)) {
27            byte[] data = SerializationUtil.serialize(in);
28            out.writeInt(data.length);
29            out.writeBytes(data);
30        }
31    }
32
33}
34

SpringMVC_RPC_Common工程RpcRequest请求类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
1package com.zhihua.common;
2
3/**
4 * RpcRequest请求类
5 * <请替换成功能描述> <br>
6 * <请替换成详细描述>
7 * @author caizh
8 * @since [1.0.0]
9 * @version [1.0.0,2017年3月24日]
10 */
11public class RpcRequest {
12
13    private String requestId;
14    private String className;
15    private String methodName;
16    private Class<?>[] parameterTypes;
17    private Object[] parameters;
18
19    public String getRequestId() {
20        return requestId;
21    }
22    public void setRequestId(String requestId) {
23        this.requestId = requestId;
24    }
25    public String getClassName() {
26        return className;
27    }
28    public void setClassName(String className) {
29        this.className = className;
30    }
31    public String getMethodName() {
32        return methodName;
33    }
34    public void setMethodName(String methodName) {
35        this.methodName = methodName;
36    }
37    public Class<?>[] getParameterTypes() {
38        return parameterTypes;
39    }
40    public void setParameterTypes(Class<?>[] parameterTypes) {
41        this.parameterTypes = parameterTypes;
42    }
43    public Object[] getParameters() {
44        return parameters;
45    }
46    public void setParameters(Object[] parameters) {
47        this.parameters = parameters;
48    }
49}
50
51

SpringMVC_RPC_Common工程RpcResponse响应类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1package com.zhihua.common;
2
3/**
4 * RpcResponse响应类
5 * <请替换成功能描述> <br>
6 * <请替换成详细描述>
7 * @author caizh
8 * @since [1.0.0]
9 * @version [1.0.0,2017年3月24日]
10 */
11public class RpcResponse {
12
13    private String requestId;
14    private Throwable error;
15    private Object result;
16
17    public String getRequestId() {
18        return requestId;
19    }
20    public void setRequestId(String requestId) {
21        this.requestId = requestId;
22    }
23    public Throwable getError() {
24        return error;
25    }
26    public void setError(Throwable error) {
27        this.error = error;
28    }
29    public Object getResult() {
30        return result;
31    }
32    public void setResult(Object result) {
33        this.result = result;
34    }
35}
36
37

SpringMVC_RPC_Common工程SerializationUtil序列化反序列化类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
1package com.zhihua.common;
2
3import java.util.Map;
4import java.util.concurrent.ConcurrentHashMap;
5
6import org.objenesis.Objenesis;
7import org.objenesis.ObjenesisStd;
8
9import com.dyuproject.protostuff.LinkedBuffer;
10import com.dyuproject.protostuff.ProtostuffIOUtil;
11import com.dyuproject.protostuff.Schema;
12import com.dyuproject.protostuff.runtime.RuntimeSchema;
13
14public class SerializationUtil {
15
16    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<>();
17
18    private static Objenesis objenesis = new ObjenesisStd(true);
19
20    private SerializationUtil() {
21    }
22
23    @SuppressWarnings("unchecked")
24    private static <T> Schema<T> getSchema(Class<T> cls) {
25        Schema<T> schema = (Schema<T>) cachedSchema.get(cls);
26        if (schema == null) {
27            schema = RuntimeSchema.createFrom(cls);
28            if (schema != null) {
29                cachedSchema.put(cls, schema);
30            }
31        }
32        return schema;
33    }
34
35    @SuppressWarnings("unchecked")
36    public static <T> byte[] serialize(T obj) {
37        Class<T> cls = (Class<T>) obj.getClass();
38        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
39        try {
40            Schema<T> schema = getSchema(cls);
41            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
42        } catch (Exception e) {
43            throw new IllegalStateException(e.getMessage(), e);
44        } finally {
45            buffer.clear();
46        }
47    }
48
49    public static <T> T deserialize(byte[] data, Class<T> cls) {
50        try {
51            T message = (T) objenesis.newInstance(cls);
52            Schema<T> schema = getSchema(cls);
53            ProtostuffIOUtil.mergeFrom(data, message, schema);
54            return message;
55        } catch (Exception e) {
56            throw new IllegalStateException(e.getMessage(), e);
57        }
58    }
59}
60
61

服务接口实现工程SpringMVC_RPC_Service_Impl :

主要放置SpringMVC_RPC_Service接口的实现类,这个工程会依赖公共RPC服务工程SpringMVC_RPC_Server

SpringMVC_RPC_Service_Impl 工程目录结构图

SpringMVC_RPC_Service_Impl 服务实现工程pom.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2  <modelVersion>4.0.0</modelVersion>
3  <parent>
4    <groupId>com.zhihua</groupId>
5    <artifactId>SpringMVC_RPC_Parent</artifactId>
6    <version>0.0.1-SNAPSHOT</version>
7  </parent>
8  <artifactId>SpringMVC_RPC_Service_Impl</artifactId>
9  <packaging>war</packaging>
10  <dependencies>
11        <dependency>
12            <groupId>com.zhihua</groupId>
13            <artifactId>SpringMVC_RPC_Server</artifactId>
14            <version>0.0.1-SNAPSHOT</version>
15        </dependency>
16        <dependency>
17            <groupId>org.springframework</groupId>
18            <artifactId>spring-webmvc</artifactId>
19            <version>4.0.1.RELEASE</version>
20        </dependency>
21        <!-- Servlet核心包 -->
22        <dependency>
23            <groupId>javax.servlet</groupId>
24            <artifactId>javax.servlet-api</artifactId>
25            <version>3.0.1</version>
26            <scope>provided</scope>
27        </dependency>
28        <dependency>
29            <groupId>com.zhihua</groupId>
30            <artifactId>SpringMVC_RPC_Service</artifactId>
31            <version>0.0.1-SNAPSHOT</version>
32        </dependency>
33    </dependencies>
34    <build>
35        <defaultGoal>compile</defaultGoal>
36        <plugins>
37            <plugin>
38                <groupId>org.apache.maven.plugins</groupId>
39                <artifactId>maven-source-plugin</artifactId>
40                <version>2.2.1</version>
41                <executions>
42                    <execution>
43                        <id>attach-sources</id>
44                        <goals>
45                            <goal>jar</goal>
46                        </goals>
47                    </execution>
48                </executions>
49            </plugin>
50            <plugin>
51                <groupId>org.apache.tomcat.maven</groupId>
52                <artifactId>tomcat8-maven-plugin</artifactId>
53                <version>2.2</version>
54                <configuration>
55                    <port>8000</port>
56                    <path>/</path>
57                </configuration>
58            </plugin>
59        </plugins>
60    </build>
61
62</project>
63

SpringMVC_RPC_Service_Impl工程HelloServiceImpl服务实现类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
1package com.zhihua.service.Impl;
2
3import java.util.ArrayList;
4import java.util.Calendar;
5import java.util.Date;
6import java.util.List;
7
8import com.zhihua.annotation.RpcService;
9import com.zhihua.entity.User;
10import com.zhihua.service.IHelloService;
11
12/**
13 * 指定远程接口 使用RpcService注解定义在服务接口的实现类上
14 * 需要对该实现类指定远程接口,因为实现类可能会实现多个接口,一定要告诉框架哪个才是远程接口。
15 * <请替换成功能描述> <br>
16 * <请替换成详细描述>
17 * @author caizh
18 * @since [1.0.0]
19 * @version [1.0.0,2017年3月24日]
20 */
21@RpcService(IHelloService.class)
22public class HelloServiceImpl implements IHelloService{
23
24    @Override
25    public String hello(String name) {
26        String result = "hello" + name;
27        System.out.println(result);
28        return "hello" + name;
29    }
30
31    @Override
32    public User getUser(String name) {
33        User user = new User(name,new Date(),true);
34        return user;
35    }
36
37    @Override
38    public List<User> getUsers(int size) {
39        List<User> list = new ArrayList<User>();
40        User user = null;
41        String name = "foo";
42        Date birthday = new Date();
43        Calendar cal = Calendar.getInstance();
44        cal.setTime(birthday);
45        for(int i = 0; i < size; i++){
46            cal.add(Calendar.DAY_OF_MONTH, 1);
47            user = new User(name, cal.getTime(), i%2==0 ? true : false);
48            list.add(user);
49        }
50        return list;
51    }
52
53    @Override
54    public User updateUser(User user) {
55        user.setName(user.getName()+"--update");
56        return user;
57    }
58
59} 
60

SpringMVC_RPC_Service_Impl工程 RpcBootstrap 启动服务器并发布服务

为了加载 applicationContext.xml 配置文件来发布服务,只需编写一个引导程序即可:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1package com.zhihua.bootstrap;
2
3import org.springframework.context.support.ClassPathXmlApplicationContext;
4
5/**
6 * 运行RpcBootstrap类的main方法即可启动服务端
7 * <请替换成功能描述> <br>
8 * <请替换成详细描述>
9 * @author caizh
10 * @since [1.0.0]
11 * @version [1.0.0,2017年5月16日]
12 */
13public class RpcBootstrap {
14
15    @SuppressWarnings("resource")
16    public static void main(String[] args) {
17        try {
18            System.out.println("服务器正在启动!");
19            if(new ClassPathXmlApplicationContext("applicationContext.xml")!=null){
20                System.out.println("服务器启动成功!");
21            }
22        } catch (Exception e) {
23            System.out.println("服务器启动失败!");
24            System.out.println(e.getMessage());
25        }          
26    }
27}
28

SpringMVC_RPC_Service_Impl工程配置文件config.properties


1
2
3
4
5
6
7
1# ZooKeeper 服务器
2registry.address=127.0.0.1:2181
3
4# RPC 服务器
5server.address=127.0.0.1:8000
6#以上配置表明:连接本地的 ZooKeeper 服务器,并在 8000 端口上发布 RPC 服务。
7

SpringMVC_RPC_Service_Impl工程 applicationContext.xml 配置文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4    xmlns:context="http://www.springframework.org/schema/context"
5    xmlns:tx="http://www.springframework.org/schema/tx"
6    xmlns:aop="http://www.springframework.org/schema/aop"
7    xsi:schemaLocation="http://www.springframework.org/schema/beans
8    http://www.springframework.org/schema/beans/spring-beans.xsd
9        http://www.springframework.org/schema/tx
10        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
11        http://www.springframework.org/schema/context
12        http://www.springframework.org/schema/context/spring-context-4.0.xsd
13        http://www.springframework.org/schema/aop
14        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
15
16    <!-- 自动扫描web包 ,将带有注解的类 纳入spring容器管理 -->
17    <context:component-scan base-package="com.zhihua.*"/>
18    <context:property-placeholder location="classpath:config.properties"/>  
19    <context:annotation-config/>          
20
21    <!-- 配置服务注册组件 -->
22    <bean id="serviceRegistry" class="com.zhihua.server.ServiceRegistry">
23        <constructor-arg name="registryAddress" value="${registry.address}"/>
24    </bean>
25
26    <!-- 配置RPC服务器 -->
27    <bean id="rpcServer" class="com.zhihua.server.RpcServer">
28        <constructor-arg name="serverAddress" value="${server.address}"/>
29        <constructor-arg name="serviceRegistry" ref="serviceRegistry"/>
30    </bean>
31
32
33</beans>
34

服务的注册与发现工程 SpringMVC_RPC_Server :

SpringMVC_RPC_Server 主要是连接Zookeeper实现服务的注册与发现

SpringMVC_RPC_Server 工程的目录结构图

SpringMVC_RPC_Server工程pom.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3    <modelVersion>4.0.0</modelVersion>
4    <parent>
5        <groupId>com.zhihua</groupId>
6        <artifactId>SpringMVC_RPC_Parent</artifactId>
7        <version>0.0.1-SNAPSHOT</version>
8    </parent>
9    <artifactId>SpringMVC_RPC_Server</artifactId>
10    <packaging>jar</packaging>
11    <properties>
12        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13    </properties>
14    <dependencies>
15        <dependency>
16            <groupId>com.zhihua</groupId>
17            <artifactId>SpringMVC_RPC_Common</artifactId>
18            <version>0.0.1-SNAPSHOT</version>
19        </dependency>
20
21        <!-- ZooKeeper -->
22        <dependency>
23            <groupId>org.apache.zookeeper</groupId>
24            <artifactId>zookeeper</artifactId>
25            <version>3.4.6</version>
26        </dependency>
27
28        <!-- Apache Commons Collections -->
29        <dependency>
30            <groupId>org.apache.commons</groupId>
31            <artifactId>commons-collections4</artifactId>
32            <version>4.0</version>
33        </dependency>
34    </dependencies>
35</project>
36

SpringMVC_RPC_Server工程RpcServer服务启动类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
1package com.zhihua.server;
2
3import java.util.HashMap;
4import java.util.Map;
5
6import org.apache.commons.collections4.MapUtils;
7import org.slf4j.Logger;
8import org.slf4j.LoggerFactory;
9import org.springframework.beans.BeansException;
10import org.springframework.beans.factory.InitializingBean;
11import org.springframework.context.ApplicationContext;
12import org.springframework.context.ApplicationContextAware;
13
14import com.zhihua.annotation.RpcService;
15import com.zhihua.common.RpcDecoder;
16import com.zhihua.common.RpcEncoder;
17import com.zhihua.common.RpcRequest;
18import com.zhihua.common.RpcResponse;
19
20import io.netty.bootstrap.ServerBootstrap;
21import io.netty.channel.ChannelFuture;
22import io.netty.channel.ChannelInitializer;
23import io.netty.channel.ChannelOption;
24import io.netty.channel.EventLoopGroup;
25import io.netty.channel.nio.NioEventLoopGroup;
26import io.netty.channel.socket.SocketChannel;
27import io.netty.channel.socket.nio.NioServerSocketChannel;
28
29/**
30 * RpcServer服务启动类
31 * <请替换成功能描述> <br>
32 * <请替换成详细描述>
33 * @author caizh
34 * @since [1.0.0]
35 * @version [1.0.0,2017年3月24日]
36 */
37public class RpcServer implements ApplicationContextAware,InitializingBean{
38
39    private static final Logger LOGGER = LoggerFactory.getLogger(RpcServer.class);
40
41    private String serverAddress;
42    private ServiceRegistry serviceRegistry;
43
44    private Map<String, Object> handlerMap = new HashMap<>(); // 存放接口名与服务对象之间的映射关系
45
46    public RpcServer(String serverAddress) {
47        this.serverAddress = serverAddress;
48    }
49
50    public RpcServer(String serverAddress, ServiceRegistry serviceRegistry) {
51        this.serverAddress = serverAddress;
52        this.serviceRegistry = serviceRegistry;
53    }
54
55    @Override
56    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
57        Map<String, Object> serviceBeanMap = ctx.getBeansWithAnnotation(RpcService.class); // 获取所有带有 RpcService 注解的 Spring Bean
58        if (MapUtils.isNotEmpty(serviceBeanMap)) {
59            for (Object serviceBean : serviceBeanMap.values()) {
60                String interfaceName = serviceBean.getClass().getAnnotation(RpcService.class).value().getName();
61                handlerMap.put(interfaceName, serviceBean);
62            }
63        }
64    }
65
66    @Override
67    public void afterPropertiesSet() throws Exception {
68        EventLoopGroup bossGroup = new NioEventLoopGroup();
69        EventLoopGroup workerGroup = new NioEventLoopGroup();
70        try {
71            ServerBootstrap bootstrap = new ServerBootstrap();
72            bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
73            .childHandler(new ChannelInitializer<SocketChannel>() {
74                @Override
75                public void initChannel(SocketChannel channel) throws Exception {
76                    channel.pipeline()
77                    .addLast(new RpcDecoder(RpcRequest.class)) // 将 RPC 请求进行解码(为了处理请求)
78                    .addLast(new RpcEncoder(RpcResponse.class)) // 将 RPC 响应进行编码(为了返回响应)
79                    .addLast(new RpcHandler(handlerMap)); // 处理 RPC 请求
80                }
81            })
82            .option(ChannelOption.SO_BACKLOG, 128)
83            .childOption(ChannelOption.SO_KEEPALIVE, true);
84
85            String[] array = serverAddress.split(":");
86            String host = array[0];
87            int port = Integer.parseInt(array[1]);
88
89            ChannelFuture future = bootstrap.bind(host, port).sync();
90            LOGGER.debug("server started on port {}", port);
91
92            if (serviceRegistry != null) {
93                serviceRegistry.register(serverAddress); // 注册服务地址
94            }
95
96            future.channel().closeFuture().sync();
97        } finally {
98            workerGroup.shutdownGracefully();
99            bossGroup.shutdownGracefully();
100        }
101    }
102}
103
104

SpringMVC_RPC_Server工程ServiceRegistry服务注册类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
1package com.zhihua.server;
2
3import java.io.IOException;
4import java.util.concurrent.CountDownLatch;
5
6import org.apache.zookeeper.CreateMode;
7import org.apache.zookeeper.KeeperException;
8import org.apache.zookeeper.WatchedEvent;
9import org.apache.zookeeper.Watcher;
10import org.apache.zookeeper.ZooDefs;
11import org.apache.zookeeper.ZooKeeper;
12import org.slf4j.Logger;
13import org.slf4j.LoggerFactory;
14
15import com.zhihua.common.Constant;
16
17/**
18 * 服务注册类
19 * <请替换成功能描述> <br>
20 * <请替换成详细描述>
21 * @author caizh
22 * @since [1.0.0]
23 * @version [1.0.0,2017年3月27日]
24 */
25public class ServiceRegistry {
26
27    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistry.class);
28
29    private CountDownLatch latch = new CountDownLatch(1);
30
31    private String registryAddress;
32
33    public ServiceRegistry(String registryAddress) {
34        this.registryAddress = registryAddress;
35    }
36
37    public void register(String data) {
38        if (data != null) {
39            ZooKeeper zk = connectServer();
40            if (zk != null) {
41                createNode(zk, data);
42            }
43        }
44    }
45
46    private ZooKeeper connectServer() {
47        ZooKeeper zk = null;
48        try {
49            zk = new ZooKeeper(registryAddress, Constant.ZK_SESSION_TIMEOUT, new Watcher() {
50                @Override
51                public void process(WatchedEvent event) {
52                    if (event.getState() == Event.KeeperState.SyncConnected) {
53                        latch.countDown();
54                    }
55                }
56            });
57            latch.await();
58        } catch (IOException | InterruptedException e) {
59            LOGGER.error("", e);
60        }
61        return zk;
62    }
63
64    private void createNode(ZooKeeper zk, String data) {
65        try {
66            byte[] bytes = data.getBytes();
67            String path = zk.create(Constant.ZK_DATA_PATH, bytes, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
68            LOGGER.debug("create zookeeper node ({} => {})", path, data);
69        } catch (KeeperException | InterruptedException e) {
70            LOGGER.error("", e);
71        }
72    }
73
74}
75

SpringMVC_RPC_Server工程RpcHandler请求统一处理类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
1package com.zhihua.server;
2
3import java.util.Map;
4
5import org.slf4j.Logger;
6import org.slf4j.LoggerFactory;
7import org.springframework.cglib.reflect.FastClass;
8import org.springframework.cglib.reflect.FastMethod;
9
10import com.zhihua.common.RpcRequest;
11import com.zhihua.common.RpcResponse;
12
13import io.netty.channel.ChannelFutureListener;
14import io.netty.channel.ChannelHandlerContext;
15import io.netty.channel.SimpleChannelInboundHandler;
16
17/**
18 * RpcHandler请求统一处理类
19 * <请替换成功能描述> <br>
20 * <请替换成详细描述>
21 * @author caizh
22 * @since [1.0.0]
23 * @version [1.0.0,2017年3月24日]
24 */
25public class RpcHandler extends SimpleChannelInboundHandler<RpcRequest> {
26
27    /**
28     * 为了避免使用Java反射带来的性能的问题,我们可以使用CGLib提供的反射API,如上面用到的FastClass与FastMethod
29     */
30    private static final Logger LOGGER = LoggerFactory.getLogger(RpcHandler.class);
31
32    private final Map<String, Object> handlerMap;
33
34    public RpcHandler(Map<String, Object> handlerMap) {
35        this.handlerMap = handlerMap;
36    }
37
38    @Override
39    public void channelRead0(final ChannelHandlerContext ctx, RpcRequest request) throws Exception {
40        RpcResponse response = new RpcResponse();
41        response.setRequestId(request.getRequestId());
42        try {
43            Object result = handle(request);
44            response.setResult(result);
45        } catch (Throwable t) {
46            response.setError(t);
47        }
48        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
49    }
50
51    private Object handle(RpcRequest request) throws Throwable {
52        String className = request.getClassName();
53        Object serviceBean = handlerMap.get(className);
54
55        Class<?> serviceClass = serviceBean.getClass();
56        String methodName = request.getMethodName();
57        Class<?>[] parameterTypes = request.getParameterTypes();
58        Object[] parameters = request.getParameters();
59
60        /*Method method = serviceClass.getMethod(methodName, parameterTypes);
61      method.setAccessible(true);
62      return method.invoke(serviceBean, parameters);*/
63
64        FastClass serviceFastClass = FastClass.create(serviceClass);
65        FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);
66        return serviceFastMethod.invoke(serviceBean, parameters);
67    }
68
69    @Override
70    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
71        LOGGER.error("server caught exception", cause);
72        ctx.close();
73    }
74}
75

至此,服务端代码编写完毕,接下来开始编写客户端代码

客户端工程SpringMVC_RPC_Client:

主要是springMVC实现服务端服务接口的调用测试

SpringMVC_RPC_Client工程目录结构图

SpringMVC_RPC_Client工程的pom.xml文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3    <modelVersion>4.0.0</modelVersion>
4    <parent>
5        <groupId>com.zhihua</groupId>
6        <artifactId>SpringMVC_RPC_Parent</artifactId>
7        <version>0.0.1-SNAPSHOT</version>
8    </parent>
9    <artifactId>SpringMVC_RPC_Client</artifactId>
10    <packaging>war</packaging>
11    <dependencies>
12        <dependency>
13            <groupId>junit</groupId>
14            <artifactId>junit</artifactId>
15            <version>3.8.1</version>
16            <scope>test</scope>
17        </dependency>
18        <dependency>
19            <groupId>com.zhihua</groupId>
20            <artifactId>SpringMVC_RPC_Common</artifactId>
21            <version>0.0.1-SNAPSHOT</version>
22        </dependency>
23        <dependency>
24            <groupId>com.zhihua</groupId>
25            <artifactId>SpringMVC_RPC_Service</artifactId>
26            <version>0.0.1-SNAPSHOT</version>
27        </dependency>
28        <dependency>
29            <groupId>javax.servlet</groupId>
30            <artifactId>javax.servlet-api</artifactId>
31            <version>3.1.0</version>
32            <scope>provided</scope>
33        </dependency>
34        <!-- Spring -->
35        <dependency>
36            <groupId>org.springframework</groupId>
37            <artifactId>spring-context</artifactId>
38            <version>4.0.1.RELEASE</version>
39        </dependency>
40        <dependency>
41            <groupId>org.springframework</groupId>
42            <artifactId>spring-webmvc</artifactId>
43            <version>4.0.1.RELEASE</version>
44        </dependency>
45        <dependency>
46            <groupId>org.springframework</groupId>
47            <artifactId>spring-test</artifactId>
48            <version>4.0.1.RELEASE</version>
49            <scope>test</scope>
50        </dependency>
51
52        <!-- ZooKeeper -->
53        <dependency>
54            <groupId>org.apache.zookeeper</groupId>
55            <artifactId>zookeeper</artifactId>
56            <version>3.4.6</version>
57        </dependency>
58
59        <!-- CGLib -->
60        <dependency>
61            <groupId>cglib</groupId>
62            <artifactId>cglib</artifactId>
63            <version>3.1</version>
64        </dependency>
65    </dependencies>
66
67</project>
68

SpringMVC_RPC_Client工程HelloController类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
1package com.zhihua.controller;
2
3import java.util.Date;
4import java.util.List;
5
6import org.springframework.beans.factory.annotation.Autowired;
7import org.springframework.stereotype.Controller;
8import org.springframework.web.bind.annotation.RequestMapping;
9
10import com.zhihua.client.RpcProxy;
11import com.zhihua.entity.User;
12import com.zhihua.service.IHelloService;
13
14@Controller
15public class HelloController {
16
17    @Autowired
18    private RpcProxy rpcProxy;
19
20    @RequestMapping("/hello")
21    public void hello(String name){
22        IHelloService service = rpcProxy.create(IHelloService.class);
23        String result = service.hello(name);
24        System.out.println(result);
25    }
26
27    @RequestMapping("/getUser")
28    public void getUser(String name){
29        IHelloService service = rpcProxy.create(IHelloService.class);
30        System.out.println(service.getUser(name).toString());
31    }
32
33    @RequestMapping("/getUsers")
34    public void getUsers(int size){
35        IHelloService service = rpcProxy.create(IHelloService.class);
36        List<User> list = service.getUsers(size);
37        for(User user : list){
38            System.out.println(user.toString());
39        }
40    }
41
42    @RequestMapping("/updateUser")
43    public void updateUser(String name){
44        User user = new User(name, new Date(), true);
45        IHelloService service = rpcProxy.create(IHelloService.class);
46        user = service.updateUser(user);
47        System.out.println(user.toString());
48    }
49
50    @RequestMapping("/test")
51    public void test(){
52        System.out.println("测试路径");
53    }
54}
55

SpringMVC_RPC_Client工程代理类RpcProxy


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
1package com.zhihua.client;
2
3import java.lang.reflect.Method;
4import java.util.UUID;
5
6import com.zhihua.common.RpcRequest;
7import com.zhihua.common.RpcResponse;
8
9import net.sf.cglib.proxy.InvocationHandler;
10import net.sf.cglib.proxy.Proxy;
11
12public class RpcProxy {
13
14    private String serverAddress;
15    private ServiceDiscovery serviceDiscovery;
16
17    public RpcProxy(String serverAddress) {
18        this.serverAddress = serverAddress;
19    }
20
21    public RpcProxy(ServiceDiscovery serviceDiscovery) {
22        this.serviceDiscovery = serviceDiscovery;
23    }
24
25    @SuppressWarnings("unchecked")
26    public <T> T create(Class<?> interfaceClass) {
27        return (T) Proxy.newProxyInstance(
28                interfaceClass.getClassLoader(),
29                new Class<?>[]{interfaceClass},
30                new InvocationHandler() {
31                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
32                        RpcRequest request = new RpcRequest(); // 创建并初始化 RPC 请求
33                        request.setRequestId(UUID.randomUUID().toString());
34                        request.setClassName(method.getDeclaringClass().getName());
35                        request.setMethodName(method.getName());
36                        request.setParameterTypes(method.getParameterTypes());
37                        request.setParameters(args);
38
39                        if (serviceDiscovery != null) {
40                            serverAddress = serviceDiscovery.discover(); // 发现服务
41                        }
42
43                        String[] array = serverAddress.split(":");
44                        String host = array[0];
45                        int port = Integer.parseInt(array[1]);
46
47                        RpcClient client = new RpcClient(host, port); // 初始化 RPC 客户端
48                        RpcResponse response = client.send(request); // 通过 RPC 客户端发送 RPC 请求并获取 RPC 响应
49
50                        if (response.getError() != null) {
51                            throw response.getError();
52                        } else {
53                            return response.getResult();
54                        }
55                    }
56                }
57                );
58    }
59
60}
61

SpringMVC_RPC_Client工程客户端类RpcClient


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
1package com.zhihua.client;
2
3import org.slf4j.Logger;
4import org.slf4j.LoggerFactory;
5
6import com.zhihua.common.RpcDecoder;
7import com.zhihua.common.RpcEncoder;
8import com.zhihua.common.RpcRequest;
9import com.zhihua.common.RpcResponse;
10
11import io.netty.bootstrap.Bootstrap;
12import io.netty.channel.ChannelFuture;
13import io.netty.channel.ChannelHandlerContext;
14import io.netty.channel.ChannelInitializer;
15import io.netty.channel.ChannelOption;
16import io.netty.channel.EventLoopGroup;
17import io.netty.channel.SimpleChannelInboundHandler;
18import io.netty.channel.nio.NioEventLoopGroup;
19import io.netty.channel.socket.SocketChannel;
20import io.netty.channel.socket.nio.NioSocketChannel;
21
22public class RpcClient extends SimpleChannelInboundHandler<RpcResponse>{
23
24    private static final Logger LOGGER = LoggerFactory.getLogger(RpcClient.class);
25
26
27    private String host;
28    private int port;
29
30    private RpcResponse response;
31
32    private final Object obj = new Object();
33
34    public RpcClient(String host, int port) {
35        this.host = host;
36        this.port = port;
37    }
38
39    @Override
40    public void channelRead0(ChannelHandlerContext ctx, RpcResponse response) throws Exception {
41        this.response = response;
42
43        synchronized (obj) {
44            obj.notifyAll(); // 收到响应,唤醒线程
45        }
46    }
47
48    @Override
49    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
50        LOGGER.error("client caught exception", cause);
51        ctx.close();
52    }
53
54    public RpcResponse send(RpcRequest request) throws Exception {
55        EventLoopGroup group = new NioEventLoopGroup();
56        try {
57            Bootstrap bootstrap = new Bootstrap();
58            bootstrap.group(group).channel(NioSocketChannel.class)
59            .handler(new ChannelInitializer<SocketChannel>() {
60                @Override
61                public void initChannel(SocketChannel channel) throws Exception {
62                    channel.pipeline()
63                    .addLast(new RpcEncoder(RpcRequest.class)) // 将 RPC 请求进行编码(为了发送请求)
64                    .addLast(new RpcDecoder(RpcResponse.class)) // 将 RPC 响应进行解码(为了处理响应)
65                    .addLast(RpcClient.this); // 使用 RpcClient 发送 RPC 请求
66                }
67            })
68            .option(ChannelOption.SO_KEEPALIVE, true);
69
70            ChannelFuture future = bootstrap.connect(host, port).sync();
71            future.channel().writeAndFlush(request).sync();
72
73            synchronized (obj) {
74                obj.wait(); // 未收到响应,使线程等待
75            }
76
77            if (response != null) {
78                future.channel().closeFuture().sync();
79            }
80            return response;
81        } finally {
82            group.shutdownGracefully();
83        }
84    }
85}
86

SpringMVC_RPC_Client工程服务发现类ServiceDiscovery


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
1package com.zhihua.client;
2
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.List;
6import java.util.concurrent.CountDownLatch;
7
8import org.apache.zookeeper.KeeperException;
9import org.apache.zookeeper.WatchedEvent;
10import org.apache.zookeeper.Watcher;
11import org.apache.zookeeper.ZooKeeper;
12import org.slf4j.Logger;
13import org.slf4j.LoggerFactory;
14
15import com.zhihua.common.Constant;
16
17import io.netty.util.internal.ThreadLocalRandom;
18
19public class ServiceDiscovery {
20
21    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceDiscovery.class);
22
23    private CountDownLatch latch = new CountDownLatch(1);
24
25    private volatile List<String> dataList = new ArrayList<>();
26
27    private String registryAddress;
28
29    public ServiceDiscovery(String registryAddress) {
30        this.registryAddress = registryAddress;
31
32        ZooKeeper zk = connectServer();
33        if (zk != null) {
34            watchNode(zk);
35        }
36    }
37
38    public String discover() {
39        String data = null;
40        int size = dataList.size();
41        if (size > 0) {
42            if (size == 1) {
43                data = dataList.get(0);
44                LOGGER.debug("using only data: {}", data);
45            } else {
46                data = dataList.get(ThreadLocalRandom.current().nextInt(size));
47                LOGGER.debug("using random data: {}", data);
48            }
49        }
50        return data;
51    }
52
53    private ZooKeeper connectServer() {
54        ZooKeeper zk = null;
55        try {
56            zk = new ZooKeeper(registryAddress, Constant.ZK_SESSION_TIMEOUT, new Watcher() {
57                @Override
58                public void process(WatchedEvent event) {
59                    if (event.getState() == Event.KeeperState.SyncConnected) {
60                        latch.countDown();
61                    }
62                }
63            });
64            latch.await();
65        } catch (IOException | InterruptedException e) {
66            LOGGER.error("", e);
67        }
68        return zk;
69    }
70
71    private void watchNode(final ZooKeeper zk) {
72        try {
73            List<String> nodeList = zk.getChildren(Constant.ZK_REGISTRY_PATH, new Watcher() {
74                @Override
75                public void process(WatchedEvent event) {
76                    if (event.getType() == Event.EventType.NodeChildrenChanged) {
77                        watchNode(zk);
78                    }
79                }
80            });
81            List<String> dataList = new ArrayList<>();
82            for (String node : nodeList) {
83                byte[] bytes = zk.getData(Constant.ZK_REGISTRY_PATH + "/" + node, false, null);
84                dataList.add(new String(bytes));
85            }
86            LOGGER.debug("node data: {}", dataList);
87            this.dataList = dataList;
88        } catch (KeeperException | InterruptedException e) {
89            LOGGER.error("", e);
90        }
91    }
92}
93

SpringMVC_RPC_Client工程配置文件config.properties


1
2
3
1# ZooKeeper 服务器
2registry.address=127.0.0.1:2181
3

SpringMVC_RPC_Client工程 applicationContext.xml 配置文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4    xmlns:context="http://www.springframework.org/schema/context"
5    xmlns:tx="http://www.springframework.org/schema/tx"
6    xmlns:aop="http://www.springframework.org/schema/aop"
7    xsi:schemaLocation="http://www.springframework.org/schema/beans
8    http://www.springframework.org/schema/beans/spring-beans.xsd
9        http://www.springframework.org/schema/tx
10        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
11        http://www.springframework.org/schema/context
12        http://www.springframework.org/schema/context/spring-context-4.0.xsd
13        http://www.springframework.org/schema/aop
14        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
15
16    <!-- 自动扫描web包 ,将带有注解的类 纳入spring容器管理 -->
17    <context:component-scan base-package="com.zhihua.*"/>
18    <context:property-placeholder location="classpath:config.properties"/>  
19    <context:annotation-config/>
20
21    <!-- 完成请求和注解POJO的映射 -->
22    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
23
24    <!-- 配置服务发现组件 -->
25    <bean id="serviceDiscovery" class="com.zhihua.client.ServiceDiscovery">
26        <constructor-arg name="registryAddress" value="${registry.address}"/>
27    </bean>
28
29    <!-- 配置 RPC代理 -->
30    <bean id="rpcProxy" class="com.zhihua.client.RpcProxy">
31        <constructor-arg name="serviceDiscovery" ref="serviceDiscovery"/>
32    </bean>
33
34</beans>
35

至此,客户端代码编写完毕,接下来就是测试了

注意:

  • 因为该例都是在本地上测试的,所以在测试的时候,一定要确认本地的 ZooKeeper 是打开的,否则实例是运行不成功的
  • 在运行SpringMVC_RPC_Client工程前,要先把其他工程打包,先执行SpringMVC_RPC_Service_Impl工程中的RpcBootstrap 的main方法,启动服务,然后在tomcat中部署SpringMVC_RPC_Client
  • 说一下我在执行测试过程中碰到的问题:在执行的时候,一直报错,找不到 IHelloService这个接口,可我已经在pom文件中引用了SpringMVC_RPC_Service工程依赖,引用本身也没有问题,百度也没出结果,最后我直接SpringMVC_RPC_Client添加了之前已经打包的SpringMVC_RPC_Service,就不再报错,测试通过

测试结果:

http://localhost:8090/SpringMVC_RPC_Client/hello?name=aaaaa

helloaaaaa

http://localhost:8090/SpringMVC_RPC_Client/getUsers?size=5

{“birthday”:1495094682365,”name”:”foo”,”sex”:true} {“birthday”:1495181082365,”name”:”foo”,”sex”:false} {“birthday”:1495267482365,”name”:”foo”,”sex”:true} {“birthday”:1495353882365,”name”:”foo”,”sex”:false} {“birthday”:1495440282365,”name”:”foo”,”sex”:true}

给TA打赏
共{{data.count}}人
人已打赏
安全经验

Google Adsense老手经验

2021-10-11 16:36:11

安全经验

安全咨询服务

2022-1-12 14:11:49

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索