@Import interpretation and annotation @ImportResource

Foreword

When using Spring-Cloud micro-services framework for @Import and @ImportResource two notes surely we are not unfamiliar. We will often use @Import to import a class or the like introduced with a @Component Spring annotation to be placed in a container class; @ImportResource be introduced by a conventional xml configuration file. In addition, when you enable many components, we will use a form as @EnableXXX annotations, such as @ EnableAsync, @ EnableHystrix, @ EnableApollo etc., opening these annotations inside retroactive, you will find @Import figure. It seems that these two notes and we usually closely related to the development, but we know how they play a role in it? Here's explore together.

text

First look at the paths of these two notes, which are located under org.springframework.context.annotation package, it can be said is the root seedlings of red Spring notes, so these two annotation process, more is in the original Spring carried out the frame. Spring-Cloud run method starts class by simply retrace our method can be targeted to the run (only part of the code):

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();

It can be seen at position 19 rows, call refreshContext method, see here, presumably think of Spring in the famous refresh method, indeed, it is the completion of a call to refresh method in which this method. These two annotation process, should still fall refresh method.

protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }

        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }

Can see that this method might create three ApplicationContext, but these are three ways to construct a container of view, are found in each constructor initializes a AnnotationBeanDefinitionReader, so metaprocessor class ConfigurationClassPostProcessor is so loaded into a container .

The same thing I read through the blog we know, is the fifth method refresh method invokeBeanFactoryPostProcessors (beanFactory) to complete a call to the class ConfigurationClassPostProcessor in postProcessBeanDefinitionRegistry methods. We focus on a call to parse.parse () method, as shown below:

// 初始化解析器
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

        SET <BeanDefinitionHolder> a LinkedHashSet candidates in a new new = <BeanDefinitionHolder> (configCandidates);
        SET <ConfigurationClass> = alreadyParsed new new HashSet <ConfigurationClass> (configCandidates.size ());
        do {
            // parse, this method is the core of the post-processing method after a long analysis of complex batch
            parser.parse (candidates);

This method is very complex, but it can not stop the pace of our progress, continue to view it. Found later transferred org.springframework.context.annotation.ConfigurationClassParser # doProcessConfigurationClass method that a large amount of content, respectively @ PropertySource, @ Import, @ ImportSource, @ Bean has been processed, we traced back to @ImportResource for example, because @Import compared @ImportResource just one step less parsing Xml file.

Navigate to the place of processing @ImportResource:

// 将解析结果添加到ConfigurationClass的importedResources中
        if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
            AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
            String[] resources = importResource.getAliasedStringArray("locations", ImportResource.class, sourceClass);
            Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
            for (String resource : resources) {
                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
                configClass.addImportedResource(resolvedResource, readerClass);
            }
        }

May know, here are extracted every resource xml configuration item @ImportResource out, with the reader put together a map configClass in. There have taken into, taken place following the parse method, as follows:

parser.parse(candidates);
            parser.validate();

            Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
            configClasses.removeAll(alreadyParsed);

            // Read the model and create bean definitions based on its content
            if (this.reader == null) {
                this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
            }
            // 将BeanDefinition加载进容器中
            this.reader.loadBeanDefinitions(configClasses);

Line 14 into the traceability code point, will find the following:

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
            TrackedConditionEvaluator trackedConditionEvaluator) {

        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName());
            return;
        }

        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

Line 19 is taken out before the code is put into the data, the method calls loadBeanDefinitions XmlBeanDefinitionReader loading process is performed. And here you can see @Import treatment, the treatment of ImportBeanDefinitionRegistrars.

Here, Spring containers to complete the processing of the @ Import, @ ImportResource annotation, all the classes involved are stored in the container. Where there is little need to mention is that in the process of @Import notes when a recursive call with the cycle, because there may be @ Import, @ ImportResource and other notes, to do so on @Import incoming class will not be able to guarantee missing.

Well, the basic interpretation on here, if one has inaccuracies, also please correct me fellow.

Guess you like

Origin www.linuxidc.com/Linux/2019-08/160331.htm