preface

After finishing the two short topics of cluster fault tolerance and service publishing principles, a friend of mine asked me when service references start. This is a primer on service references. Before, I have been looking at the source code with everyone. Since Talk is cheap.Show me your code, so this article will write the code with everyone.

We interrupt the interview questions

  • How does Dubbo work? Please talk about it briefly

  • Have you ever considered implementing an RPC framework like Dubbo yourself? If so, how would you implement it? (Interview frequency questions, high distinction)

  • You said you used Mybatis, then you know the principle of Mapper interface? (If the answer is good and the keyword dynamic proxy is mentioned further, how is this dynamic proxy injected into the Mapper interface via dependency injection?)

Straight into the theme

Simple principle

When we talk about dubbo, we must first understand the basic concept of dubbo, colloquially speaking, is what dubbo is

Dubbo is a distributed services framework dedicated to providing high-performance and transparent RPC remote service invocation solutions, as well as SOA service governance solutions

Before we get there, it’s important to mention a few simple and confusing concepts

  • The cluster

The same service is deployed on multiple servers

  • distributed

A service is divided into multiple sub-services and deployed on different servers

  • RPC

Remote Procedure Call Protocol (RPC) : Remote Procedure Call

We captured several important keywords, distributed, transparent,RPC.

Since each service is deployed on different servers, the call between services is to communicate through the network, which is simply described as follows:

Before in [dubbo source code parsing – local exposure] when there were a lot of friends asked, this local exposure has what use. First of all,dubbo is a widely used framework, so every bit of performance improvement can benefit a large number of people. That’s why the JDK source code is all about bitwise operations. For example, the UserService and RoleService are in the same module, and their direct communication performance is much better over the JVM than over the network. That’s why dubbo is designed to have both remote and local exposure.

That involves network communication, service consumers before invoking a service network to write all kinds of requests, relevant code codec, obviously, it is very unfriendly. Dubbo transparent, is refers to, let the caller requests to the network, codecs, such as the details of the transparent, let us like calls to the local service calls to the remote service, even feel himself in Use remote services.

All that said, how exactly do you do that? To implement this requirement, we can easily think of a key word, that is dynamic proxy

public interface MenuService {
    void sayHello(a);
}
Copy the code
public class MenuServiceImpl implements MenuService{
    @Override
    public void sayHello(a) {}}Copy the code
public class ProxyFactory implements InvocationHandler {
    private Class interfaceClass;
    public ProxyFactory(Class interfaceClass) {
        this.interfaceClass = interfaceClass;
    }
    // Return the proxy Object, which is generic in order to call it without strong casting. Object requires strong casting
    public <T> T getProxyObject(a){
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),// Class loader
                new Class[]{interfaceClass},// Which interfaces to proxy for (which methods to block)
                this);//(where to intercept these methods)
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method);
        System.out.println("Encode.");
        System.out.println("Send network request");
        System.out.println("Decode and return the network request result.");
        return null; }}Copy the code
public void test(a) throws Exception {
    ProxyFactory proxyFactor = new ProxyFactory(MenuService.class);
    MenuService menuService = proxyFactor.getProxyObject();
    menuService.sayHello();
    // The output is as follows:
    //public abstract void com.toby.rpc.MenuService.sayHello()
    // Encode
    // Send a network request
    // Decodes the network request result and returns it
}
Copy the code

See here may have a friend to ridicule, I have seen you a few months of source code analysis, the above I would have understood, then I also pay attention to fat toward the public number why. What I want is a complete framework similar to Dubbo, which is not very good in performance, or at least similar in appearance and use. For example, we usually use Dubbo in configuration file configuration

<dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService"/>
Copy the code

And then used in @autoWired dependency injection to use, frankly, forced grid have!

With the spring

If we want to write a simple RPC, we will call it tobyRPC(Fat face English name toby). In fact, I personally prefer screenshots, but some friends and I repeatedly emphasize the code, so HERE I will stick code

1. Design configuration properties and Javabeans

public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean {
    @Override
    public Object getObject(a) throws Exception {
        return get();
    }
    @Override
    publicClass<? > getObjectType() {return getInterfaceClass();
    }
    @Override
    public boolean isSingleton(a) {
        return true; }}Copy the code
public class ReferenceConfig<T> {
    privateClass<? > interfaceClass;// Interface proxy class reference
    private transient volatile T ref;
    public synchronized T get(a) {
        if (ref == null) {
            init();
        }
        return ref;
    }
    private void init(a) {
        ref = new ProxyFactory(interfaceClass).getProxyObject();
    }
    publicClass<? > getInterfaceClass() {return interfaceClass;
    }
    public void setInterfaceClass(Class
        interfaceClass) {
        this.interfaceClass = interfaceClass; }}Copy the code

2. Write an XSD file

<?xml version="1.0" encoding="UTF-8" standalone="no"? >
<xsd:schema
        xmlns="http://toby.com/schema/tobyRPC"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:beans="http://www.springframework.org/schema/beans"
        xmlns:tool="http://www.springframework.org/schema/tool"
        targetNamespace="http://toby.com/schema/tobyRPC">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
    <xsd:import namespace="http://www.springframework.org/schema/beans"/>
    <xsd:import namespace="http://www.springframework.org/schema/tool"/>

    <xsd:complexType name="referenceType">
        <xsd:complexContent>
            <xsd:extension base="beans:identifiedType">
                <xsd:attribute name="interface" type="xsd:token" use="required">
                    <xsd:annotation>
                        <xsd:documentation><! [CDATA[ The service interface class name. ]]></xsd:documentation>
                        <xsd:appinfo>
                            <tool:annotation>
                                <tool:expected-type type="java.lang.Class"/>
                            </tool:annotation>
                        </xsd:appinfo>
                    </xsd:annotation>
                </xsd:attribute>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:element name="reference" type="referenceType">
        <xsd:annotation>
            <xsd:documentation><! [CDATA[ Reference service config ]]></xsd:documentation>
        </xsd:annotation>
    </xsd:element>

</xsd:schema>
Copy the code

3. Write NamespaceHandler and BeanDefinitionParser to complete parsing

public class TobyRPCBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    protected Class getBeanClass(Element element) {
        return ReferenceBean.class;
    }
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        String interfaceClass = element.getAttribute("interface");
        if (StringUtils.hasText(interfaceClass)) {
            bean.addPropertyValue("interfaceClass", interfaceClass); }}}Copy the code
public class TobyRPCNamespaceHandler extends NamespaceHandlerSupport {
    public void init(a) {
        registerBeanDefinitionParser("reference".newTobyRPCBeanDefinitionParser()); }}Copy the code

4. Write spring. Handlers and spring

spring.handlers

http\://toby.com/schema/tobyRPC=com.toby.config.TobyRPCNamespaceHandler
Copy the code

spring.schemas

http\://toby.com/schema/tobyRPC.xsd=META-INF/tobyRPC.xsd
Copy the code

5. Create a configuration file

<?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:tobyRPC="http://toby.com/schema/tobyRPC"
	xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://toby.com/schema/tobyRPC http://toby.com/schema/tobyRPC.xsd">
	
	<tobyRPC:reference id="menuService" interface="com.toby.rpc.MenuService" />
	
</beans>
Copy the code

The demo structure screenshot is as follows:

We’re all set. Let’s run a unit test

It worked as we expected. But how to encode it, how to send the request, how to decode it doesn’t seem to say. Don’t say? After completing the service reference topic, I will focus on the source code of dubbo codec, SPI, Javassist and other key content. After I have mastered the idea of the whole framework, I will copy a simple dubbo framework with all five aspects (including design mode and Dubbo architecture design) by hand. In a word, pay attention to the fat public number.

Type on the blackboard and underline

Why interview all like to ask principle, is all to pretend force? Of course not, understand the principle, many things are one-size-fits-all. Let’s look at this interview question from Mybatis. The principle of first Mapper interfaces, you can refer to my previous graphic source | MyBatis Mapper principle To put it simply, you inject a proxy object into the Mapper interface, and the dynamic proxy object invocation method is intercepted into an Invoke method that does something indescribable (old drivers can do whatever they want). The premise of all this is to inject dynamic proxy objects silently. In fact, the principle of injection is the same as Dubbo. Let’s look at two diagrams

Write in the last