Dubbo Bean load
Dubbo is used in conjunction with Spring, and the most common way to do this is to configure dubbo in XML. Let’s see how Spring loads Dubbo beans. Let’s look at a basic configuration of Dubbo beans. The following example is from the official example
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder/>
<dubbo:application name="demo-provider"/>
<dubbo:registry address="Zookeeper: / / ${zookeeper. Address: 127.0.0.1} : 2181"/>
<bean id="demoService" class="org.apache.dubbo.samples.serialization.impl.DemoServiceImpl"/>
<dubbo:service interface="org.apache.dubbo.samples.serialization.api.DemoService" ref="demoService"
serialization="java"/>
</beans>
Copy the code
- Write a Java Bean;
- Write an XSD file;
- Write tag parser, implement BeanDefinitionParser interface;
- Write NamespaceHandlerSupport to register tag parser, inherit NamespaceHandlerSupport, rewrite init method, register custom tag parser;
- Write spring. Handlers and spring. Schemas;
Once you’ve developed your custom tags, you can use them in your Spring configuration file. Through the dubbo spring. The handlers file find the class tag parser with com. Alibaba. Dubbo. Config. Spring. The schema. DubboNamespaceHandler. By the following code you can see, the dubbo registered 10 custom tags, labels, in addition to an annotation DubboBeanDefinitionParser parser parsed should be used in other tags, After parsing Dubbo’s Spring custom tags, you create objects and assign properties during spring container startup.
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
@Override
public void init(a) {
registerBeanDefinitionParser("application".new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module".new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry".new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor".new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider".new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer".new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol".new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service".new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference".new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation".newAnnotationBeanDefinitionParser()); }}Copy the code
The core classes for Dubbo producers and consumers are ServiceBean and ReferenceBean, respectively, which are loaded when Spring parses the < Dubbo :service or < Dubbo: Reference tag. The inheritance structure of these two classes is as follows:
- ServiceBean
- ReferenceBean
Dubbo start
In the dubbo bean loading section above, we learned that Dubbo loads beans through Spring custom tags during application startup. Let’s look at how Dubbo starts.
Start listening DubboBootstrapApplicationListener Dubbo client
The previous section described how dubbo’s core beans have been created through spring custom tags, and dubbo’s client is started. Dubbo uses the ApplicationListener interface, which implements Spring’s listener interface, to listen for events completed by the Refresh of the Spring container. When the Spring container is refreshed, Dubbo listens to perform Dubbo client startup as follows:
public class DubboBootstrapApplicationListener extends OneTimeExecutionApplicationContextEventListener
implements Ordered {
/**
* The bean name of {@link DubboBootstrapApplicationListener}
*
* @since2.7.6 * /
public static final String BEAN_NAME = "dubboBootstrapApplicationListener";
private final DubboBootstrap dubboBootstrap;
public DubboBootstrapApplicationListener(a) {
// Get the DubboBootstrap object, which will load the Environment, ConfigManager, via SPI
this.dubboBootstrap = DubboBootstrap.getInstance();
}
@Override
public void onApplicationContextEvent(ApplicationContextEvent event) {
// Handle ContextRefreshedEvent time. This event is the time when the Spring container finishes refreshing
if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
} else if (event instanceof ContextClosedEvent) {
// Handle ContextClosedEvent time, Spring context close eventonContextClosedEvent((ContextClosedEvent) event); }}// Spring context refresh completion event
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
dubboBootstrap.start();
}
// The Spring context closure event
private void onContextClosedEvent(ContextClosedEvent event) {
dubboBootstrap.stop();
}
@Override
public int getOrder(a) {
returnLOWEST_PRECEDENCE; }}abstract class OneTimeExecutionApplicationContextEventListener implements ApplicationListener.ApplicationContextAware {
private ApplicationContext applicationContext;
public final void onApplicationEvent(ApplicationEvent event) {
if (isOriginalEventSource(event) && event instanceofApplicationContextEvent) { onApplicationContextEvent((ApplicationContextEvent) event); }}/**
* The subclass overrides this method to handle {@link ApplicationContextEvent}
*
* @param event {@link ApplicationContextEvent}
*/
protected abstract void onApplicationContextEvent(ApplicationContextEvent event);
/**
* Is original {@link ApplicationContext} as the event source
*
* @param event {@link ApplicationEvent}
* @return* /
private boolean isOriginalEventSource(ApplicationEvent event) {
return (applicationContext == null) // Current ApplicationListener is not a Spring Bean, just was added
// into Spring's ConfigurableApplicationContext
|| Objects.equals(applicationContext, event.getSource());
}
@Override
public final void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getApplicationContext(a) {
returnapplicationContext; }}Copy the code
After the Spring container is refreshed, the event code is as follows:
/**
* Finish the refresh of this context, invoking the LifecycleProcessor's
* onRefresh() method and publishing the
* {@link org.springframework.context.event.ContextRefreshedEvent}.
*/
protected void finishRefresh(a) {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event. Publish ContextRefreshedEvent
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
Copy the code
Dubbo start DubboBootstrap# start ()
public DubboBootstrap start(a) {
// Whether it has been started
if (started.compareAndSet(false.true)) {
ready.set(false);
/ / initialization
initialize();
if (logger.isInfoEnabled()) {
logger.info(NAME + " is starting...");
}
Publish the Dubbo service
exportServices();
// Not only Provider register, the original data is published once
if(! isOnlyRegisterProvider() || hasExportedServices()) {// 2. Publish metadata
exportMetadataService();
//3. Register the local ServiceInstance if required
registerServiceInstance();
}
referServices();
if (asyncExportingFutures.size() > 0) {
new Thread(() -> {
try {
this.awaitFinish();
} catch (Exception e) {
logger.warn(NAME + " exportAsync occurred an exception.");
}
ready.set(true);
if (logger.isInfoEnabled()) {
logger.info(NAME + " is ready.");
}
}).start();
} else {
ready.set(true);
if (logger.isInfoEnabled()) {
logger.info(NAME + " is ready."); }}if (logger.isInfoEnabled()) {
logger.info(NAME + " has started."); }}return this;
}
Copy the code
conclusion
Dubbo + Spring’s Bean loading process uses custom tags to load beans. Dubbo spring-based custom tag standard implements the parser DubboBeanDefinitionParser and AnnotationBeanDefinitionParser, through the bean label parsing created, assignment and initialization of the life cycle of treatment, Dubbo implements the Spring listener ApplicationListener, which listens for events when the Spring container is refreshed, and starts the Dubbo client after the Spring container is refreshed to register, publish, subscribe, etc.