接上一篇《11.手写rpc框架-代码实现(四)》
上一篇我们编写了注册中心rpc-registry-zookeeper,来实现服务的注册和发现。那么至此,框架层的工程代码都已经完成,下面我们来编写引用框架层的客户端rpc-sample-client和提供具体服务的rpc-sample-server服务端以及定义公共服务规范的rpc-sample-api工程。
注:代码参考http://git.oschina.net/huangyong/rpc(作者:黄勇)
因为rpc-sample-client客户端调用的Service服务,以及rpc-sample-server提供的Service服务必须是一致的,两者各自制定一样的规范会很难保持一致,所以这里我们需要第三方工程制定Service服务的规范,于是就有了api规范的工程rpc-sample-api,下面我们来编写它。
在MyEclipse新建名为rpc-sample-api的maven工程:
新建成功后,由于该工程只是Service服务接口规范,不需要任何的实现,所以POM文件中无需引入其它依赖:
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xxx.rpc</groupId>
<artifactId>rpc-framework</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>rpc-sample-api</artifactId>
<build/>
</project>
然后我们开始编写代码,这里我们需要一个测试服务HelloService接口,以及一个实体类Person。所以我们在src/main/java中创建com.xxx.rpc.api包下的HelloService、Person:
package com.xxx.rpc.sample.api;
public interface HelloService {
String hello(String name);
String hello(Person person);
}
在HelloService接口中我们定义了两个hello方法,一个是传入String字符串,反馈一个新String字符串;一个是传入Person对象,反馈一个String字符串。下面是上述接口参数中的Person的Bean类:
package com.xxx.rpc.sample.api;
public class Person {
private String firstName;
private String lastName;
public Person(){}
public Person(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
该Bean定义了一个名字首部和名字尾部的参数,并且编写了构造函数用户初始化这两个参数。
api服务接口定义工程编写完毕,下面我们来编写具体的服务提供方rpc-sample-server工程。
在MyEclipse新建名为rpc-sample-server的maven工程,该工程就是以rpc-server作为父工程,实现相关服务类,并将相关服务类地址注册到注册中心:
新建成功之后,在POM中引入依赖,需要引入rpc-sample-api服务接口定义规范,以及rpc-server父级工程来实现Netty服务交换以及服务注册。因为该工程在打包的时候,需要将一些我们自己编写的依赖放到指定目录,所以在build中需要添加依赖的copy规则插件以及编译相关依赖类为jar的插件:
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xxx.rpc</groupId>
<artifactId>rpc-framework</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>rpc-sample-server</artifactId>
<dependencies>
<!-- RPC Sample API -->
<dependency>
<groupId>com.xxx.rpc</groupId>
<artifactId>rpc-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- RPC Server -->
<dependency>
<groupId>com.xxx.rpc</groupId>
<artifactId>rpc-server</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Dependency -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- Jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib</classpathPrefix>
<mainClass>com.xxx.rpc.sample.server.RpcBootstrap</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
然后我们开始编写代码,这里我们要实现两个版本的HelloService服务,首先在src/main/java中创建com.xxx.rpc.sample.server包下的HelloServiceImpl和HelloServiceImpl2类:
package com.xxx.rpc.sample.server;
import com.xxx.rpc.sample.api.HelloService;
import com.xxx.rpc.sample.api.Person;
import com.xxx.rpc.server.RpcService;
@RpcService(HelloService.class) //RpcService用于暴露服务至注册中心
public class HelloServiceImpl implements HelloService{
@Override
public String hello(String name) {
return "Hello! "+name;
}
@Override
public String hello(Person person) {
return "Hello! "+ person.getFirstName() + " " + person.getLastName();
}
}
该类实现了HelloService接口的两个hello方法,分别输出了英文“Hello”加上各自的参数。最上面使用@RpcService注解,以便Spring容器可以扫描到相关类,并暴露给注册中心,里面的参数“HelloService”就是暴露给注册中心的服务名。
package com.xxx.rpc.sample.server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class RpcBootstrap {
private static final Logger LOGGER = LoggerFactory.getLogger(RpcBootstrap.class);
public static void main(String[] args) {
LOGGER.debug("start server");
new ClassPathXmlApplicationContext("spring.xml");
}
}
这里编写了mian方法用于启动服务,并使用ClassPathXmlApplicationContext加载spring配置文件,进行spring容器的初始化与加载。因为上面需要加载spring容器,这里我们在src/main/resource下创建spring配置文件“spring.xml”:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xxx.rpc.sample.server"/>
<context:property-placeholder location="classpath:rpc.properties"/>
<bean id="serviceRegistry" class="com.xxx.rpc.registry.zookeeper.ZooKeeperServiceRegistry">
<constructor-arg name="zkAddress" value="${rpc.registry_address}"/>
</bean>
<bean id="rpcServer" class="com.xxx.rpc.server.RpcServer">
<constructor-arg name="serviceAddress" value="${rpc.service_address}"/>
<constructor-arg name="serviceRegistry" ref="serviceRegistry"/>
</bean>
</beans>
这里首先我们使用“context:component-scan”标签进行了包扫描,以扫描出带有“RpcServer”注解的服务类加入到Spring容器中(因为RpcServer注解类本身实现了@Component注解,所以会被Spring容器扫描到)。然后加载rpc.properties配置文件,该文件存放了后面的两个参数“${rpc.registry_address}”和“${rpc.service_address}”,分别是rpc注册中心地址,和提供服务的服务地址(即本工程部署的地址);然后就是实现rpc-server引入的rpc-registry-zookeeper工程中的注册中心操作类,并为其指定其成员变量zkAddress注册中心地址的值。最后就是实现rpc-server的rpcServer类,并为其注入serviceAddress服务地址以及注册中心操作类serviceRegistry。
上面的rpc.properties文件配置如下(放置在spring.xml同级目录):
rpc.service_address=127.0.0.1:8000
rpc.registry_address=127.0.0.1:2181
在其中指定了rpc注册中心地址,和提供服务的服务地址(即本工程部署的地址)。最后因为使用到了日志类,需要生产相关日志以供生产问题分析,这里我们创建log4j的日志配置文件“log4j.properties”:
log4j.rootLogger=ERROR,console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%m%n
log4j.logger.com.xxx.rpc=DEBUG
这里指定log4j的根配置为ERROR级别,console控制台打印。然后是log4j的日志打印纸控制台的设置。
最后指定com.xxx.rpc日志打印级别为DEBUG。
至此,一个接入rpc-server工程的服务实现实例工程rpc-sample-server编写完毕。
下一篇我们来完成最后一个工程,即接入了rpc-client工程的服务调用客户端实例工程rpc-sample-client。
转载请注明出处:https://blog.csdn.net/acmman/article/details/89280964