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