接上文【转】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}