Welcome to the public number [sharedCode] committed to mainstream middleware source analysis, you can contact me directly

preface

In previous articles, we looked at how Spring interprets the @Service, @Reference annotation. Today we’ll focus on a very important class for the Service exposed, ServiceBean, which generates a ServiceBean for every exposed Service.

ServiceBean

The inheritance implementation relationship for this class is as follows

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean.DisposableBean.ApplicationContextAware.ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
	// code omitted
}
Copy the code

It inherits ServiceConfig, and this class is particularly important, and I’ll talk about it later, because service exposure, SPI mechanisms, are associated with this class

InitializingBean mainly uses its afterPropertiesSet method, which is called after the object has been instantiated to initialize some values

DisposableBean, primarily using its destroy() method, called at Spring container Showdown.

ApplicationContextAware, in order to get applicationContext

ApplicationListener, which adds a context refresh listener to expose service usage.

BeanNameAware, which sets the name of the Bean

setApplicationContext

@Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
      	// Set applicationContext to SpringExtensionFactory for subsequent Bean retrieval from SpringExtensionFactory
        //SpringExtensionFactory is a dubbo custom class
        SpringExtensionFactory.addApplicationContext(applicationContext);
        if(applicationContext ! =null) {
            SPRING_CONTEXT = applicationContext;
            try {
                Method method = applicationContext.getClass().getMethod("addApplicationListener".newClass<? >[]{ApplicationListener.class});/ / compatible Spring2.0.1
              	AddApplicationListener (ApplicationListener
       listener),
                // Then add the current class (because it listens for ContextRefreshedEvent events) to spring's listener list
                method.invoke(applicationContext, new Object[]{this});
                supportedApplicationListener = true;
            } catch (Throwable t) {
                if (applicationContext instanceof AbstractApplicationContext) {
                    try {
                        Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener".newClass<? >[]{ApplicationListener.class});/ / compatible Spring2.0.1
                        if(! method.isAccessible()) { method.setAccessible(true);
                        }
                        method.invoke(applicationContext, new Object[]{this});
                        supportedApplicationListener = true;
                    } catch (Throwable t2) {
                    }
                }
            }
        }
    }
Copy the code

SpringExtensionFactory is used for dependency injection in Dubbo’s SPI mechanism. When an extension class needs to inject another bean, You might fetch the Bean object from the SpringExtensionFactory class through the applicationContext.

onApplicationEvent

@Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // The service is not lazily loaded && the service is not published && the service is not offline. Service exposure occurs when these three conditions are met
        if(isDelay() && ! isExported() && ! isUnexported()) {if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            // Expose the service interfaceexport(); }}private boolean isDelay(a) {
      	// Get lazy loading Settings, delay registering service time (ms)-, set to -1, delay exposing service until Spring container initialization is complete
        Integer delay = getDelay();
        ProviderConfig provider = getProvider();
        if (delay == null&& provider ! =null) {
            delay = provider.getDelay();
        }
        // Add context refresh listener, and do not set lazy loading,
        return supportedApplicationListener && (delay == null || delay == -1);
    }
Copy the code

The above export method is more important and is used for service exposure, which will be discussed separately later.

afterPropertiesSet

Dubbo calls back to the class that implements the InitializingBean when Spring instantiates the bean (initializeBean). The callback method is this method

@Override
    @SuppressWarnings({"unchecked", "deprecation"})
    public void afterPropertiesSet(a) throws Exception {
        // 
        if (getProvider() == null) {
            Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false.false);
            if(providerConfigMap ! =null && providerConfigMap.size() > 0) {
                Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false.false);
                if ((protocolConfigMap == null || protocolConfigMap.size() == 0)
                        && providerConfigMap.size() > 1) { // backward compatibility
                    List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if(config.isDefault() ! =null&& config.isDefault().booleanValue()) { providerConfigs.add(config); }}if (!providerConfigs.isEmpty()) {
                        setProviders(providerConfigs);
                    }
                } else {
                    ProviderConfig providerConfig = null;
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() == null || config.isDefault().booleanValue()) {
                            if(providerConfig ! =null) {
                                throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and "+ config); } providerConfig = config; }}if(providerConfig ! =null) { setProvider(providerConfig); }}}}// If the current ServiceBan application is empty, set application for the Service
        if (getApplication() == null
                && (getProvider() == null || getProvider().getApplication() == null)) {
            Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false.false);
            if(applicationConfigMap ! =null && applicationConfigMap.size() > 0) {
                ApplicationConfig applicationConfig = null;
                for (ApplicationConfig config : applicationConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        if(applicationConfig ! =null) {
                            throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and "+ config); } applicationConfig = config; }}if(applicationConfig ! =null) { setApplication(applicationConfig); }}}// If the current module of ServiceBan is empty, set the module for the Service
        if (getModule() == null
                && (getProvider() == null || getProvider().getModule() == null)) {
            Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false.false);
            if(moduleConfigMap ! =null && moduleConfigMap.size() > 0) {
                ModuleConfig moduleConfig = null;
                for (ModuleConfig config : moduleConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        if(moduleConfig ! =null) {
                            throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and "+ config); } moduleConfig = config; }}if(moduleConfig ! =null) { setModule(moduleConfig); }}}// If the current ServiceBan Registries is empty, set Registries for the Service
        if ((getRegistries() == null || getRegistries().isEmpty())
                && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().isEmpty())
                && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) {
            Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false.false);
            if(registryConfigMap ! =null && registryConfigMap.size() > 0) {
                List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
                for (RegistryConfig config : registryConfigMap.values()) {
                    if (config.isDefault() == null|| config.isDefault().booleanValue()) { registryConfigs.add(config); }}if(registryConfigs ! =null && !registryConfigs.isEmpty()) {
                    super.setRegistries(registryConfigs); }}}// If the current ServiceBan Monitor is empty, set the Monitor for the Service
        if (getMonitor() == null
                && (getProvider() == null || getProvider().getMonitor() == null)
                && (getApplication() == null || getApplication().getMonitor() == null)) {
            Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false.false);
            if(monitorConfigMap ! =null && monitorConfigMap.size() > 0) {
                MonitorConfig monitorConfig = null;
                for (MonitorConfig config : monitorConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        if(monitorConfig ! =null) {
                            throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and "+ config); } monitorConfig = config; }}if(monitorConfig ! =null) { setMonitor(monitorConfig); }}}// If the current Protocol of ServiceBan is empty, set Protocol for the Service
        if ((getProtocols() == null || getProtocols().isEmpty())
                && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().isEmpty())) {
            Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false.false);
            if(protocolConfigMap ! =null && protocolConfigMap.size() > 0) {
                List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
                for (ProtocolConfig config : protocolConfigMap.values()) {
                    if (config.isDefault() == null|| config.isDefault().booleanValue()) { protocolConfigs.add(config); }}if(protocolConfigs ! =null && !protocolConfigs.isEmpty()) {
                    super.setProtocols(protocolConfigs); }}}// Set the service name
        if (getPath() == null || getPath().length() == 0) {
            if(beanName ! =null && beanName.length() > 0&& getInterface() ! =null && getInterface().length() > 0&& beanName.startsWith(getInterface())) { setPath(beanName); }}if (!isDelay()) {
            export();
        }
    }
Copy the code

Check to see if any of the ServiceBean properties (here are six) is empty, if so, get the bean of the appropriate type from applicationContext, and if so, set it accordingly.

  • ProviderConfig Provider: Indicates whether dubbo:provider is configured
  • ApplicationConfig Application: Whether dubbo:application is configured
  • ModuleConfig Module: Whether dubbo:module is configured
  • List registries: Whether dubbo:registry is configured
  • MonitorConfig Monitor: Indicates whether dubbo: indicates monitor is configured
  • List protocols: Whether dubbo:protocol is configured
  • String path: indicates the service name

That’s how you prepare for Service exposure.

Welcome to the public number [sharedCode] committed to mainstream middleware source analysis, you can contact me directly