preface
The previous article explained how dubbo-SPI is implemented. This article explains how to expose an interface service
The body of the
To start with the use of Dubbo, an XML configuration was used to configure the service:
The DemoService interface depends on the domoService bean, which means that we use the DemoService interface to request the Dubbo server, and the DemoServiceImpl implementation class will be called to handle it.
Dubbo: Service is dubbo’s custom XML method. Bean tags belong to Spring, and Spring provides custom XML parsing. Check dubbo-config-spring package.
You can see the dubo.xsd file, which specifies all the dubo-xml tags and parameters:
Look at the parser classes that spring. Handlers fill in
Using DubboBeanDefinitionParser, inherit the spring BeanDefinitionParser for XML parsing
This class is a mess of all the configuration items written together. The general idea is to parse the XML, do different parsing depending on the class type passed in, and then instantiate the class and inject values into methods that start with set or IS. As you can see from the previous figure, the Service configuration is resolved by the ServiceBean class.
The ServiceBean class inherits and implements the interface relationship as follows:
Some of spring’s inherited interfaces are bean-related, but the really useful interface is ApplicationListener. This interface is a Listener interface, and ContextRefreshedEvent indicates that the method is executed when the class is initialized
To view the method:
After the ServiceBean is initialized, check the status and start exposing the service
The export method is handed over to its parent class to execute, the ServiceBean just exists as a bean, and the ServiceConfig class does the real work
As you can see, this is the core way to expose a service. There is another way to use API configuration as opposed to XML configuration. Take a look at the comparison between XML and API configuration:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
context.start();
ServiceConfig<DemoService> serviceServiceConfig = new ServiceConfig<DemoService>();
System.in.read(); // press any key to exit
Copy the code
This is the startup class for the XML configuration method
ServiceConfig<DemoService> serviceConfig = new ServiceConfig<DemoService>();
serviceConfig.setApplication(new ApplicationConfig("app"));
serviceConfig.setRegistry(new RegistryConfig("Zookpeer: / / 127.0.0.1:2181"));
serviceConfig.setInterface(DemoService.class);
serviceConfig.setRef(new DemoServiceImpl());
serviceConfig.export();
System.in.read();
Copy the code
The ServiceConfig does not only expose the service, but also add the registry to the service
Synchronization method, judge some null values and get, the judgment of delayed attributes, the main method into doExport
This long method is mainly about monitoring, protocols, registries, interfaces, implementation classes, etc., followed by entry to doExportUrls method.
The protocols and registryURLs here correspond to these two parts of the XML, transforming the registry configuration into a URL format in the following format:
Ip-path (class name) -param, param in addition to some attributes of XML configuration, there are dubbo version, timestamp, etc.
URL, URL, URL, URL, URL, URL, URL, URL, URL, URL, URL
A URL is constructed based on different protocols and configured parameters. All the information contained in the URL is contained in the URL.
The key is this piece of code
ProxyFactory is an SPI method that uses JavassistProxyFactory by default, where param and registryURL of the url above are concatenated together
The implementation class is wrapped in a wrapper, and AbstractProxyInvoker is returned, internally calling the Wrapper’s invokeMethod method, which is similar to reflection
Inside the Wrapper
Notice the makeWrapper
Using Javassist and using Builder to construct bytecode, decompilation looks like this:
package org.apache.dubbo.common.bytecode;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.apache.dubbo.common.bytecode.ClassGenerator.DC;
import org.apache.dubbo.demo.DemoService;
public class Wrapper0 extends Wrapper implements DC {
public static String[] pns;
public static Map pts;
public static String[] mns;
public static String[] dmns;
public static Class[] mts0;
public String[] getPropertyNames() {
return pns;
}
public boolean hasProperty(String var1) {
return pts.containsKey(var1);
}
public Class getPropertyType(String var1) {
return (Class)pts.get(var1);
}
public String[] getMethodNames() {
return mns;
}
public String[] getDeclaredMethodNames() {
return dmns;
}
public void setPropertyValue(Object var1, String var2, Object var3) {
try {
DemoService var4 = (DemoService)var1;
} catch (Throwable var6) {
throw new IllegalArgumentException(var6);
}
throw new NoSuchPropertyException("Not found property \"" + var2 + "\" filed or setter method in class org.apache.dubbo.demo.DemoService.");
}
public Object getPropertyValue(Object var1, String var2) {
try {
DemoService var3 = (DemoService)var1;
} catch (Throwable var5) {
throw new IllegalArgumentException(var5);
}
throw new NoSuchPropertyException("Not found property \"" + var2 + "\" filed or setter method in class org.apache.dubbo.demo.DemoService.");
}
public Object invokeMethod(Object var1, String var2, Class[] var3, Object[] var4) throws InvocationTargetException {
DemoService var5;
try {
var5 = (DemoService)var1;
} catch (Throwable var8) {
throw new IllegalArgumentException(var8);
}
try {
if ("sayHello".equals(var2) && var3.length == 1) {
return var5.sayHello((String)var4[0]); }}catch (Throwable var9) {
throw new InvocationTargetException(var9);
}
throw new NoSuchMethodException("Not found method \"" + var2 + "\" in class org.apache.dubbo.demo.DemoService.");
}
public Wrapper0(a) {}}Copy the code
Inheriting the Wrapper, the invokeMethod method is implemented to reflect the calling method based on the name of the method. If there are multiple methods, it is just multiple if operations
Now that you’ve wrapped up the service instances that need to be exposed, let’s expose the server.
The supported protocol is shown in the package name, which defaults to Dubbo
Call the export method of Protocol to expose the service, using dubbo by default
See DubboProtocol
The main one is this openServer method
Enter the createServer
There is a binding of a server and a Hander to handle the request
Tranposrt is used and belongs to the Dubo-Remoting layer
Tranposrt is also an SPI, using Netty by default, but can also be replaced with other such as HTTP. It is constructed into a URL according to the XML configuration. The selection of different services is mainly reflected in the PARam parameter of the URL
Open a nettyServer method, and the classic Netty method is similar, mainly do some encapsulation.
At this point, a netty server has been started, bound to the specified port number, and the configured service implementation class is wrapped, through the Netty server request, filled with the specified interface name, method name, and parameters. You can get the Invoker and then call the invokeMethod method and call the methods of the implementation class, which implements RPC once