This is my 17th day of the Genwen Challenge

Handwritten RPC framework

Using ZooKeeper as the registry, RMI as the connection technology, and handwritten RPC framework. (Wang has a lot of tutorials on how to build zK, I have built them in the previous section, so I will not describe them here)

1. Create the ParentDemo project

1. Create a parent project, ParentDemo, which contains three aggregation subprojects

2. Pojo: Entity class required in service

3. Service: contains interfaces that are dependent on by ServiceImpl and Consumer

Serviceimpl: Indicates the service content provided by the provider

5. Consumer: Content invoked by the consumer

(I did not create the parent directory integration as in the course, because each project is independent in the actual development, and then added the related project dependencies in POM.xml.)

So create separate projects and integrate them

1. Create a POJO project

Create a Maven project and use SpringBoot to add dependencies directly to pom.xml

Once the project is created, the Person entity class is created in overly simple code, with just two properties and the usual getters and setters

private Integer id;
private String name;
Copy the code

2. Create a Service project

Creating the call interface

public interface MyPersonService extends Remote {

    List<Person> findAllPerson() throws RemoteException;
}
Copy the code

Create the Provider project

It was mentioned before that ZK would be used as the registry, so I used Docker to build a ZK later, and Docker was really cool

After entering the container, create the associated nodes

#Create a node at the command terminal
create /rpc
Copy the code

Provider project implementation service interface method:

@Service
public class MyPersonServiceImpl extends UnicastRemoteObject implements MyPersonService {

    public MyPersonServiceImpl(a) throws RemoteException {}

    @Override
    public List<Person> findAllPerson(a) throws RemoteException {
        // Do not join the process, directly construct data
        List<Person> personList = new ArrayList<>();
        personList.add(new Person(1."zhangsan"));
        personList.add(new Person(2."sansi"));
        returnpersonList; }}Copy the code

CountDownLatch was added in the code because it took a long time to connect to ZooKeeper, so the node was created before zK was connected, so an exception was thrown. Therefore, the lock is used to block, and the lock is not released until it is connected. I thought I could change that to make the connection faster. But if it can’t connect, it will die waiting. Use sleep delay to wait for the connection

Create a startup class, code implementation as follows:

public class ProviderRun { public static void main(String[] args) throws Exception{ CountDownLatch countDownLatch = new CountDownLatch(1); MyPersonService MyPersonService = new MyPersonServiceImpl(); / / 2. Binding port LocateRegistry. CreateRegistry (8989); / / 3. Binding address String urL = "rmi: / / localhost: 8989 / myPersonService"; Naming.bind(urL, myPersonService); System.out.println("RMI service started successfully "); ZooKeeper ZooKeeper = new ZooKeeper("192.168.1.20:2181", 10, New Watcher() {@override public void process(WatchedEvent WatchedEvent) {system.out.println (" service succeeded "); countDownLatch.countDown(); }}); If (they are) States) CONNECTING = = ZooKeeper. GetState ()) {System. Out. Println (" are connected, the block waiting for "); countDownLatch.await(); } // add the link to the zk, and the ACL is used to control permissions, such as read-only data, etc., because the connection is constantly requested, so the persistent node, in case the id keeps adding system.out.println (" start to create a node "); zooKeeper.create("/rpc/provider", urL.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println(" registered successfully "); }}Copy the code

4. Create external consumer projects

Create interfaces to present data

public interface PersonService {
    List<Person> personShow(a);
}
Copy the code

Create the PersonServiceImpl method that implements the interface

@Service
public class PersonServiceImpl implements PersonService {
    @Override
    public List<Person> personShow(a) {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        try {
            //1. Release information
            MyPersonService myPersonService = new MyPersonServiceImpl();
            //2. Bind ports
            LocateRegistry.createRegistry(8989);
            //3. Bind the address
            String urL = "rmi://localhost:8989/myPersonService";
            Naming.bind(urL, myPersonService);

            System.out.println("RMI service started successfully");

            //4. Create zK server connection and publish information
            ZooKeeper zooKeeper = new ZooKeeper("192.168.1.20:2181".10.new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    System.out.println("Service connection succeeded"); countDownLatch.countDown(); }});if (ZooKeeper.States.CONNECTING == zooKeeper.getState()) {
                System.out.println("Connecting, blocking waiting");
                countDownLatch.await();

            }

            //5. Obtain node content
            System.out.println("Start node creation");
            byte[] bytes = zooKeeper.getData("/rpc/provider".false.null);

            //6
            MyPersonService myPersonServiceList = (MyPersonService) Naming.lookup(new String(bytes));
            return myPersonServiceList.findAllPerson();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null; }}Copy the code

Like provider, the only difference is that getDate gets the data

Create the controller layer for access

@Controller
public class PersonController {

    @Autowired
    private PersonService personService;

    @RequestMapping("/show")
    @ResponseBody
    public List<Person> show(a){
        returnpersonService.personShow(); }}Copy the code

Create the corresponding ConsumerApplication class to start springBoot, adding the dependency first

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.1.11. RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.1.11. RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.4.9</version>
    </dependency>
    <dependency>
        <groupId>com.anzhi</groupId>
        <artifactId>pojo</artifactId>
        <version>1.0 the SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.anzhi</groupId>
        <artifactId>service</artifactId>
        <version>1.0 the SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.anzhi</groupId>
        <artifactId>provider</artifactId>
        <version>1.0 the SNAPSHOT</version>
    </dependency>
</dependencies>
Copy the code

Additional project dependencies are included because of the associated methods and classes used

Code implementation:

@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); }}Copy the code

Then start the project, visit http://localhost:8080/show in the browser, although you can response, but to show the Person did not appear on the page

Running terminal error message:

java.io.NotSerializableException: com.anzhi.pojo.Person
Copy the code

The Person class in POJO is not serialized. After serialization, delete the provider node in the client terminal of ZK, run ProviderRun again, and remember to close it after running, because the data of the node in Consumer is also obtained through the same port, which will lead to port conflict. So you can modify one of the ports. Turn it off if you don’t want to change it.

Then restart the ConsumerApplication for the Consumer service and visit again. The page displays JSON information for the corresponding Person class.

At this point an RPC rough framework flow is complete

(TODO persistence problem: due to THE ZK problem, the connection is extremely slow, and then the corresponding page is very slow. I didn’t find the reason, I changed the ZK version and it didn’t improve very well.)