Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Methods for exporting Dubbo services locally

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "how to export Dubbo services locally". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "how to export Dubbo services locally".

1. Find the entry method context = new ClassPathXmlApplicationContext (new String [] {"META-INF/spring/dubbo-demo-provider.xml"}) for Dubbo service export; / / delete some steps public void refresh () throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {try {/ / 1. The core code inside is to initialize applicationEventMulticaster, which is used for later release events using / / this.applicationEventMulticaster = new SimpleApplicationEventMulticaster (beanFactory); initApplicationEventMulticaster (); / / 2. Initialize the non-delay loaded bean. Here, some bean configured by dubbo, including ServiceBean, are initialized for service export finishBeanFactoryInitialization (beanFactory); / / 3. Publish the container refresh event, which is the entry finishRefresh () of the service export;}} / step 2 Analysis / / where the Spring container initializes the non-delayed loaded bean, including the represented bean// finishBeanFactoryInitialization (beanFactory) The ServiceBean object is created when the Spring container initializes the represented ServiceBean. Since ServiceBean implements the / / ApplicationContextAware interface, the Spring container will first call setApplicationContext to inject the Spring container class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware {@ Override public void setApplicationContext (ApplicationContext applicationContext) {this.applicationContext = applicationContext; / / inject Spring container SpringExtensionFactory.addApplicationContext (applicationContext) into SpringExtensionFactory. If (applicationContext! = null) {SPRING_CONTEXT = applicationContext; try {/ / method is the addListener method, which is called to add listener method.invoke (applicationContext, new Object [] {this}) to applicationEventMulticaster / /; supportedApplicationListener = true Step 3 analyze and publish related events. Here, the container refresh event finishRefresh (); protected void finishRefresh () {initLifecycleProcessor (); getLifecycleProcessor (). OnRefresh (); / / 1). Publish the container refresh event, and ServiceBean listens for the event / / ServiceBean implements ApplicationListener publishEvent (new ContextRefreshedEvent (this)); LiveBeansView.registerApplicationContext (this);} / / 2). Step 1 ends here, where you get the previous applicationEventMulticaster, which is used to publish the event getApplicationEventMulticaster (). MulticastEvent (applicationEvent, eventType); / / 3). At this point, listener is the previous call to method.invoke (applicationContext, new Object [] {this}); / / the added ServiceBean,this represents ServiceBean, that is, listener,event is the container refresh event doInvokeListener (listener,event); / / 4) at this point, finally call the onApplicationEvent method listener.onApplicationEvent (event) implemented by ServiceBean

In this way, you come to the way that Dubbo exposes the entrance to the service. This is also the entry method mentioned in the Dubbo official documentation, reference service export

Public void onApplicationEvent (ContextRefreshedEvent event) {/ / if the service is not exposed and the service is not unexposed, print the log if (isDelay () & &! isExported () & &! isUnexported ()) {if (logger.isInfoEnabled ()) {logger.info ("The service ready on spring started. Service: "+ getInterface ());} / / Export service export ();}} 2, Dubbo service export

Next, take a look at the process of exporting the service from Dubbo. The Dubbo service export process begins when the Spring container publishes a refresh event, and Dubbo executes the service export logic immediately after receiving the event. The whole logic can be divided into three parts. The first part is the pre-work, which is mainly used to check parameters and assemble URL. The second part is the export service, which includes two processes: exporting the service to local (JVM) and exporting the service to remote. The third part is to register the service with the registry for service discovery. These three parts of the code will be analyzed in detail below.

2.1. Pre-work of service export

The entry method for service export is ServiceBean's onApplicationEvent. OnApplicationEvent is an event response method that performs a service export upon receipt of a Spring context refresh event. The method code is as follows

Public void onApplicationEvent (ContextRefreshedEvent event) {/ / if the service is not exposed and the service is not unexposed, print the log if (isDelay () & &! isExported () & &! isUnexported ()) {if (logger.isInfoEnabled ()) {logger.info ("The service ready on spring started. Service: "+ getInterface ();} / / Export service export ();}}

This method first determines whether or not to export the service according to the conditions. for example, some services set deferred export, so it should not be exported here at this time. Some services have already been exported, or the current service has been unexported, and the relevant services cannot be exported again at this time. Notice the isDelay method here, which literally means "whether to delay the export of the service". Returning true means delayed export, and false means no delay in export. But the true meaning of this method is not so. When the method returns true, it means that there is no need to delay the export. When false is returned, it indicates that the export needs to be delayed. Contrary to the literal meaning, this requires everyone's attention. The front work mainly consists of two parts, namely, configuration check and URL assembly. Before exporting the service, Dubbo needs to check whether the user's configuration is reasonable or supplement the default configuration for the user. After the configuration check is complete, the next step is to assemble the URL based on these configurations. In Dubbo, the role of URL is very important. Dubbo uses URL as the configuration carrier, and all expansion points are configured through URL. This is stated in the official documentation. The following export method goes to the doExport () method.

Public synchronized void export () {if (provider! = null) {if (export = = null) {export = provider.getExport ();} if (delay = = null) {delay = provider.getDelay ();}} if (export! = null & &! export) {return } if (delay! = null & & delay > 0) {delayExportExecutor.schedule (new Runnable () {@ Override public void run () {doExport ();}, delay, TimeUnit.MILLISECONDS);} else {doExport ();}}

The following is the configuration check of the relevant analysis, more code, we need to take a patient look at it. Here is a brief summary of the logic of the configuration check, as follows:

Check the validity of the interface attribute of the dubbo:service tag. If it is illegal, an exception is thrown.

Check whether the core configuration class objects such as ProviderConfig and ApplicationConfig are empty, and if so, try to obtain the corresponding instances from other configuration class objects.

Detect and process generalization services and general service classes

Detect the local stub configuration and process it accordingly

Check ApplicationConfig, RegistryConfig and other configuration classes. If it is empty, try to create it. If it cannot be created, throwing an exception configuration check is not the focus of this article. Therefore, we do not intend to analyze the methods called by the doExport method (except the doExportUrls method). Among these methods, the logic of the other methods is not very complex except that the appendProperties method is slightly more complex. Therefore, members can make their own analysis.

Protected synchronized void doExport () {if (unexported) {throw new IllegalStateException ("Already unexported!");} if (exported) {return;} exported = true; if (interfaceName = = null | | interfaceName.length () = = 0) {/ / throw exception} checkDefault () If (provider! = null) {if (application = = null) {application = provider.getApplication ();} if (module = = null) {module = provider.getModule ();} if (registries = = null) {registries = provider.getRegistries () } if (monitor = = null) {monitor = provider.getMonitor ();} if (protocols = = null) {protocols = provider.getProtocols ();}} if (module! = null) {if (registries = = null) {registries = module.getRegistries () } if (monitor = = null) {monitor = module.getMonitor ();}} if (application! = null) {if (registries = = null) {registries = application.getRegistries ();} if (monitor = = null) {monitor = application.getMonitor () }} / / detect whether ref is a generalized service type if (ref instanceof GenericService) {/ / set interfaceClass to GenericService interfaceClass = GenericService.class; if (StringUtils.isEmpty (generic)) {/ / set generic = true generic = Boolean.TRUE.toString () }} else {try {/ / get the interface type interfaceClass = Class.forName (interfaceName, true, Thread.currentThread (). GetContextClassLoader ());} catch (ClassNotFoundException e) {throw new IllegalStateException (e.getMessage (), e) } / / check checkInterfaceAndMethods (interfaceClass, methods) for a pair of interfaceClass and necessary fields in the tag; / / check the validity of a pair of ref for checkRef (); generic = Boolean.FALSE.toString () } / / stub local is also configured with local stub if (local! = null) {if ("true" .equals (local)) {local = interfaceName + "Local";} Class localClass; try {localClass = ClassHelper.forNameWithThreadContextClassLoader (local) }} if (stub! = null) {if ("true" .equals (stub)) {stub = interfaceName + "Stub";} Class stubClass; try {stubClass = ClassHelper.forNameWithThreadContextClassLoader (stub);}} checkApplication (); checkRegistry () CheckProtocol (); appendProperties (this); / / Local stub, mock validity check checkStubAndMock (interfaceClass); if (path = = null | | path.length () = 0) {path = interfaceName;} / / core code, where doExportUrls () exposes service and registration logic; ProviderModel providerModel = new ProviderModel (getUniqueServiceName (), this, ref) ApplicationModel.initProviderModel (getUniqueServiceName (), providerModel);} 2.2.2.Multiprotocol multi-registry export service

Dubbo allows us to export services using different protocols and also allows us to register services with multiple registries. Dubbo supports multi-protocol and multi-registry in the doExportUrls method. The related code is as follows

/ * Multiprotocol multi-registry exposure service is supported * / private void doExportUrls () {/ / load registry link List registryURLs = loadRegistries (true); / / traverse protocols and expose for (ProtocolConfig protocolConfig: protocols) {doExportUrlsFor1Protocol (protocolConfig, registryURLs);} under each protocol

The above code first loads the registry link through loadRegistries, and then iterates through the ProtocolConfig collection to export each service. And register the service with the registry during the process of exporting the service. Let's first look at the logic of the loadRegistries method. You can open it first and see what you can get from this method.

Protected List loadRegistries (boolean provider) {checkRegistry (); List registryList = new ArrayList (); / / if registries is empty, return the empty collection if (registries! = null & &! registries.isEmpty ()) {/ / traverse the registry configuration collection registries for (RegistryConfig config: registries) {/ / get the address String address = config.getAddress () / / if the address is empty, set it to 0.0.0.0 if (address = = null | | address.length () = = 0) {address = Constants.ANYHOST_VALUE;} String sysaddress = System.getProperty ("dubbo.registry.address"); if (sysaddress! = null & & sysaddress.length () > 0) {address = sysaddress } / / if the address is address.length A, skip if (address.length () > 0 & &! RegistryConfig.NO_AVAILABLE.equalsIgnoreCase (address)) {Map map = new HashMap (); / / add the field information in ApplicationConfig to appendParameters (map, application) in map / / add RegistryConfig field information to map appendParameters (map, config); / / add path, protocol version map.put ("path", RegistryService.class.getName ()); map.put ("dubbo", Version.getProtocolVersion ()) Map.put (Constants.TIMESTAMP_KEY, String.valueOf (System.currentTimeMillis (); if (ConfigUtils.getPid () > 0) {map.put (Constants.PID_KEY, String.valueOf (ConfigUtils.getPid () } / / if there is no protocol in map, the default is to use the dubbo protocol if (! map.containsKey ("protocol")) {if (ExtensionLoader.getExtensionLoader (RegistryFactory.class) .hasExtension ("remote")) {map.put ("protocol", "remote") } else {map.put ("protocol", "dubbo");}} / / parses to get the URL list. Address may contain multiple registry ip, so the parsed URL list List urls = UrlUtils.parseURLs (address, map) / / traverse the URL list for (URL url: urls) {/ / set the URL protocol header to registry url = url.addParameter (Constants.REGISTRY_KEY, url.getProtocol ()) / / the protocol is set to registry here, which is why the export () method of RegistryProtocol is called later because url = url.setProtocol (Constants.REGISTRY_PROTOCOL) / / decide whether to add url to registryList by judging the conditions as follows: / / if it is a service provider, and it is a registry service or a consumer service, and it is a subscription service, add it to the registryList if ((provider & & url.getParameter (Constants.REGISTER_KEY)) True)) | | (! provider & & url.getParameter (Constants.SUBSCRIBE_KEY, true) {registryList.add (url) }} return registryList;}

ProtocolConfig mainly encapsulates the tag information, which means to expose the service using the Dubbo protocol.

Private void doExportUrlsFor1Protocol (ProtocolConfig protocolConfig, List registryURLs) {/ / get the protocol name String name = protocolConfig.getName (); / / if it is empty, it is the default dubbo if (name = = null | | name.length () = = 0) {name = "dubbo";} Map map = new HashMap (); / / sets the service provider side map.put (Constants.SIDE_KEY, Constants.PROVIDER_SIDE) Map.put (Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion ()); map.put (Constants.TIMESTAMP_KEY, String.valueOf (System.currentTimeMillis (); if (ConfigUtils.getPid () > 0) {map.put (Constants.PID_KEY, String.valueOf (ConfigUtils.getPid ();} / / this code actually completes the child node configuration information overwriting appendParameters (map, application) to the parent node AppendParameters (map, module); appendParameters (map, provider, Constants.DEFAULT_KEY); appendParameters (map, protocolConfig); appendParameters (map, this) / / if the method configuration list is not empty if (methods! = null & &! methods.isEmpty ()) {/ / traverse the method configuration list for (MethodConfig method: methods) {/ / add the method name to map appendParameters (map, method, method.getName ()); / / add the field information of the MethodConfig object to map, key = method name. Attribute name / / such as storing the corresponding MethodConfig, / / key = sayHello.retries,map = {"sayHello.retries": 2, "xxx": "yyy"} String retryKey = method.getName () + ".retry"; if (map.containsKey (retryKey)) {String retryValue = map.remove (retryKey) / / if retryValue is false, do not retry. Set the value to 0 if ("false" .equals (retryValue)) {map.put (method.getName () + ".retries", "0");}}

If (ProtocolUtils.isGeneric (generic)) {map.put (Constants.GENERIC_KEY, generic); map.put (Constants.METHODS_KEY, Constants.ANY_VALUE);} else {String revision = Version.getVersion (interfaceClass, version); if (revision! = null & & revision.length () > 0) {map.put ("revision", revision) } String [] methods = Wrapper.getWrapper (interfaceClass). GetMethodNames (); if (methods.length = = 0) {map.put (Constants.METHODS_KEY, Constants.ANY_VALUE);} else {map.put (Constants.METHODS_KEY, StringUtils.join (new HashSet (Arrays.asList (methods)), ",")) }} if (! ConfigUtils.isEmpty (token)) {if (ConfigUtils.isDefault (token)) {map.put (Constants.TOKEN_KEY, UUID.randomUUID (). ToString ());} else {map.put (Constants.TOKEN_KEY, token);}} if (Constants.LOCAL_PROTOCOL.equals (protocolConfig.getName () {protocolConfig.setRegister (false) Map.put ("notify", "false");} / / export service String contextPath = protocolConfig.getContextpath (); if ((contextPath = = null | | contextPath.length () = = 0) & & provider! = null) {contextPath = provider.getContextpath ();} String host = this.findConfigedHosts (protocolConfig, registryURLs, map); Integer port = this.findConfigedPorts (protocolConfig, name, map) URL url = new URL (name, host, port, (contextPath = = null | | contextPath.length () = = 0? "": contextPath + "/") + path, map); if (ExtensionLoader.getExtensionLoader (ConfiguratorFactory.class) .hasExtension (url.getProtocol () {url = ExtensionLoader.getExtensionLoader (ConfiguratorFactory.class) .getExtension (url.getProtocol ()) .getConfigurator (url) .configure (url) } String scope = url.getParameter (Constants.SCOPE_KEY); / / don't export when none is configured if (! Constants.SCOPE_NONE.toString (). EqualsIgnoreCase (scope)) {/ / expose to local if (! Constants.SCOPE_REMOTE.toString (). EqualsIgnoreCase (scope)) {exportLocal (url) } / / expose to remote if (! Constants.SCOPE_LOCAL.toString () .equalsIgnoreCase (scope)) {/ / later analyze}} this.urls.add (url);} 2.3.expose services locally

After the front-end work is done, you can then export the service. Service export is divided into exporting to local (JVM) and exporting to remote.

/ / expose to local if (! Constants.SCOPE_REMOTE.toString () .equalsIgnoreCase (scope)) {exportLocal (url) } private void exportLocal (URL url) {/ / if the protocol is not injvm if (! Constants.LOCAL_PROTOCOL.equalsIgnoreCase (url.getProtocol () {/ / generate a local url, change the protocol to injvm and set host and port URL local = URL.valueOf (url.toFullString ()) .setProtocol (Constants.LOCAL_PROTOCOL) .setHost (LOCALHOST) .setPort (0); ServiceClassHolder.getInstance () .pushServiceClass (getServiceClass (ref)) / / create invoker through the agent project / / then call the export method to expose the service. Generate Exporter / / the protocol here is the generated extended proxy object. For more information, https://segmentfault.com/a/1190000020384210 / / it decides which Protocol instance's export method to run according to the protocol parameter in URL at run time. Because of the preceding / / setProtocol (Constants.LOCAL_PROTOCOL), the export method Exporter exporter = protocol.export of InjvmProtocol is called here (proxyFactory.getInvoker (ref, (Class) interfaceClass, local)) / / add the generated exposers to the collection exporters.add (exporter);}}

The following two values are the specific values of url and local. Because Dubbo uses an adaptive extension mechanism, and protocol used in exportLocal (URL url) is an adaptive extension, the export method of protocol uses the protocol parameter in URL to determine which instance of protocol is generated, so you can pay attention to the URL value.

Protocol protocol = ExtensionLoader.getExtensionLoader (Protocol.class). GetAdaptiveExtension ()

Let's analyze the following code. It is the core method and is divided into two steps.

Exporter exporter = protocol.export (proxyFactory.getInvoker (ref, (Class) interfaceClass, local); 1) proxyFactory.getInvoker (ref, (Class) interfaceClass, local)-> return invoker2) protocol.export (invoker) / / step 1) Analysis / / proxyFactory is also an adaptive extension agent belt, which uses JavassistProxyFactoryproxyFactory = ExtensionLoader.getExtensionLoader (ProxyFactory.class) .getAdaptiveExtension () by default / / what is called here is JavassistProxyFactory's getInvoker method public Invoker getInvoker (T proxy, Class type, URL url) {/ / create a Wrapper object final Wrapper wrapper = Wrapper.getWrapper (proxy.getClass (). GetName (). IndexOf ('$') < 0? Proxy.getClass (): type) / / create an anonymous Invoker class object and implement the doInvoke method return new AbstractProxyInvoker (proxy, type, url) {@ Override protected Object doInvoke (T proxy, String methodName,Class [] parameterTypes) Object [] arguments) throws Throwable {/ / calls the invokeMethod method of Wrapper, and invokeMethod will eventually call the target method return wrapper.invokeMethod (proxy, methodName, parameterTypes, arguments) }};}

Invoker is a very important model in Dubbo. Invoker appears on both the service provider side and the service reference side. Invoker is described in the official documentation of Dubbo, which is quoted here. Invoker is a physical domain, it is the core model of Dubbo, other models rely on it, or converted to it, it represents an executable, you can make invoke calls to it, it may be a local implementation, it may be a remote implementation, or a cluster implementation. The getInvoker method creates an anonymous Invoker object. I understand that when you make a remote call through invoke, you will use the wrapper.invokeMethod method, while wrapper is actually a proxy class, and calling wrapper.invokeMethod will eventually take proxy, that is, the sayHello method of DemoService. The creation of Wrapper is relatively complex. You can refer to the Wrapper.getWrapper generation agent analysis of JavaAssist in Dubbo.

/ / step 2 analysis, calling InjvmProtocol's export method public Exporter export (Invoker invoker) throws RpcException {/ / this method only creates one, because it is exposed locally, so in the same jvm, there is no need for other operations return new InjvmExporter (invoker, invoker.getUrl (). GetServiceKey (), exporterMap);} so far, I believe you have a deeper understanding of "Dubbo service export to the local method", might as well do some actual operation! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report