Spring Dubbo Development Notes (2) - dubbo Initialization

Keywords: Spring Dubbo github git

Summary

Spring Dubbo is a spring-boot and dubbo-based one that I wrote myself to use the Spring boot style to use dubbo. (That is, you can understand the start-up process of Spring boot and learn about the Dubbo framework)

Project introduction:

github: https://github.com/Athlizo/spring-dubbo-parent

Code cloud: https://git.oschina.net/null_584_3382/spring-dubbo-parent

Interested friends can communicate and learn together.

Demand:

When Dubbo starts, you can start Dubbo services with your own Spring, but now you need to put the logic of Dubbo starting Spring Application Contest into Spring Boot's startup logic. (mainly for annotations)

Common interfaces

Introduce in the order of calls

ApplicationContextInitializer

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
    void initialize(C applicationContext);
}

When Spring Boot starts, it scans META-INF.spring.factories under the classpath, which has a configuration named org.springframework.context.ApplicationContextInitializer, and configures the full path names of some classes that implement the ApplicationContextInitializer interface, which Spring Boot instantiates first at startup.

ApplicationListener

As with the Application Context Initializer loading method, there is another configuration item in META-INF.spring.factories, org.springframework.context.ApplicationListener, which defines the ApplicationListener that will be initialized when SpringBook starts. Strictly speaking, Application Listener triggers the invocation logic (triggered by various events) when the Spring Application Context starts up.

BeanFactoryPostProcessor

public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

As can be seen from the name, the class of this interface mainly operates on BeanFactory. Unlike the way of instantiating Application Context Initializer, this interface must exist in BeanFactory before it can be started. Therefore, what the Application Context Initializer often does is to add some BeanFactory PostProcessor.

BeanPostProcessor

public interface BeanPostProcessor {
         // Prior to afterProperties Set () and init-method
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

If BeanFactoryPostProcessor is for BeanFactory, then BeanPostProcessor is for all beans in BeanFactory. Relevant processing before and after bean initialization is provided respectively. Like BeanFactoryPostProcessor, it also needs to be registered in BeanFactory during startup to take effect, usually through BeanFactoryPostProcessor.

Summary

From the above analysis, we can see that

  • If you need to do something when initializing Spring Application, use Application Context Initializer
  • If there are some customized processes at all stages of Spring startup, use Application Listener
  • If you need to do something about BeanFactory, such as adding some beans, use BeanFactoryPostProcessor
  • If you need to do some processing of beans in BeanFactory, use BeanPostProcessor. (Personally, it is understood that the interface is mainly for batch processing of beans, otherwise InitializeBean s or Init-method are used to complete the initialization logic for specific beans.)

SpringBoot Access to Dubbo

Note: The access here is mainly for the use of annotations.

Dubbo handles @Service and @Reference

Key classes: com.alibaba.dubbo.config.spring.AnnotationBean The code logic is relatively simple. This class implements two interfaces, BeanFactoryPostProcessor and BeanPostProcessor, respectively.

  • After BeanFactory processing is completed, scan the class annotated by Service and add it to BeanFactory
  • Before Bean initialization, create a remote call proxy class and inject the set method and properties of the @Reference annotation
  • After Bean initialization, expose the class annotated by @Service to remotely invoke the service (generate Exporter)

Therefore, the key to SpringBook access to dubbo is to add AnnotationBean to BeanFactory before completing the BeanFactoryPostProcessor call

Access mode

Instead of using AnnotationBean directly, we define a new class named AnnotationBeanProcessor (for the convenience of posting code), which serves the same purpose but modifies some of the processing logic inside.

Method 1. Using Application Context Initializer

The code is as follows

public class DubboContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    public void initialize(ConfigurableApplicationContext applicationContext) {
        AnnotationBeanProcessor annotationBeanProcessor= new AnnotationBeanProcessor(${Structural parameters});
        annotationBeanProcessor.setApplicationContext(applicationContext);
        applicationContext.addBeanFactoryPostProcessor(annotationBeanProcessor);
    }
}

Characteristic - Simple Violence

Method 2 uses BeanFactoryPostProcessor

Add another BeanFactoryPostProcessor to the Application Context Initializer, and then add Annotation BeanProcessor to the BeanFactoryPostProcessor

public class DubboContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    public void initialize(ConfigurableApplicationContext applicationContext) {
        DubboBeanDefinitionRegistryPostProcessor dubboBeanDefinitionRegistryPostProcessor = new DubboBeanDefinitionRegistryPostProcessor();
        applicationContext.addBeanFactoryPostProcessor(dubboBeanDefinitionRegistryPostProcessor);
    }

    public class DubboBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClass(AnnotationBeanProcessor.class);
            beanDefinition.getConstructorArgumentValues()
                    .addGenericArgumentValue(${Structural parameters});
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            registry.registerBeanDefinition("annotationBeanProcessor", beanDefinition);
        }   
    }
}

Features: Although it feels a little winding, the advantage is that it can be executed after some other key Bean Definition Registry Post Processor, so that we can use the xxAware interface, Spring will automatically help us inject. You can take advantage of some of Spring's convenience features. Although it can be done with Application Listener, it is not recommended.

Method 3 uses ImportBean Definition Registrar

@ Import annotations add ImportBean Definition Registrar implementation class to achieve the development of the bean definition level.

public class AnnotationBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    private String BEAN_NAME = "annotationBeanProcessor";

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        List<String> basePackages = getPackagesToScan(importingClassMetadata);
        if (!registry.containsBeanDefinition(BEAN_NAME)) {
            addPostProcessor(registry, basePackages);
        }
    }

    // register annotationBeanProcessor.class
    private void addPostProcessor(BeanDefinitionRegistry registry, List<String> basePackages) {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(AnnotationBeanProcessor.class);
        beanDefinition.getConstructorArgumentValues()
                .addGenericArgumentValue(basePackages);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
    }

    //Get the scan packet path
    private List<String> getPackagesToScan(AnnotationMetadata metadata) {
        //EnableDubbo is a comment that opens a bean that scans dubbo and can define its own scan base Packages
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                metadata.getAnnotationAttributes(EnableDubbo.class.getName()));
        String[] basePackages = attributes.getStringArray("basePackages");
        return Arrays.asList(basePackages);
    }
}

EnableDubbo.class is also used, which is actually a comment that defines the properties of basePackages. Features: 1. Whether Dubbo works through annotations or not, you can configure the scanning package path of the base Packages by yourself without writing dead in the code. 2. Very Spring Boot Style

@ Reference and @Service

  • @ The set method and attributes of the Reference annotation, Dubbo creates the Reference Bean (proxy class) and injects it in.
  • @ Service is the initialization of a bean, which generates a Service Bean and then exporter (listening for remote call requests).

The ideal way to handle these two processes is in BeanPost Processor, because the above two processing logic is not for a particular bean, but for all beans, as long as there is @Reference or @Service, and meet the basepackage limit.

The existing logic of dubbo is to perform @Reference-related processes before all beans are initialized, and call the @Service process after all beans are initialized. (These two processes are even performed after the Application Context initialization is successful, and there are benefits to doing so.)

Posted by webtuto on Mon, 15 Apr 2019 13:33:33 -0700