【RPC高性能框架总结】12.手写rpc框架-代码实现(五)

接上一篇《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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

光仔December

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值