SPRING源码分析(四)之@Configuration @Bean的方式配置bean

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

在微服务大趋势下Springboot,Springcloud成为更多公司新项目技术框架的选型 ,Springboot简洁的基本零配置,很重要的一点是将以前通过xml方式配置bean转换为

通过@Configuration @Bean的方式来进行,今天主要分析下Spring是如何来实现对这两个注解进行处理的

通过Springboot的启动来跟踪分析容器的启动(这里只是简单的带过,后面会在springboot源码分析中,详细讲解),run方法具体实现如下:

    public ConfigurableApplicationContext run(String... args) {
            if (this.running.get()) {
                // If already created we just return the existing context
                return this.context;
            }
            configureAsChildIfNecessary(args);
            if (this.running.compareAndSet(false, true)) {
                synchronized (this.running) {
                    // 如果容器未启动,启动容器,装配资源
                    this.context = build().run(args);
                }
            }
            return this.context;
        }
    public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            FailureAnalyzers analyzers = null;
            configureHeadlessProperty();
            SpringApplicationRunListeners listeners = getRunListeners(args);
            listeners.starting();
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                        args);
                ConfigurableEnvironment environment = prepareEnvironment(listeners,
                        applicationArguments);
                Banner printedBanner = printBanner(environment);//打印beanner
                context = createApplicationContext();//创建默认的上下文
                analyzers = new FailureAnalyzers(context);
                prepareContext(context, environment, listeners, applicationArguments,
                        printedBanner);
                refreshContext(context);// 刷新容器
                afterRefresh(context, applicationArguments);
                listeners.finished(context, null);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    new StartupInfoLogger(this.mainApplicationClass)
                            .logStarted(getApplicationLog(), stopWatch);
                }
                return context;
            }
            catch (Throwable ex) {
                handleRunFailure(context, listeners, analyzers, ex);
                throw new IllegalStateException(ex);
            }
        }

重点关注refreshContext,在refreshContext中 就有第一篇中分析容器入口的refresh方法

    private void refreshContext(ConfigurableApplicationContext context) {
            refresh(context);
            if (this.registerShutdownHook) {
                try {
                    context.registerShutdownHook();
                }
                catch (AccessControlException ex) {
                    // Not allowed in some environments.
                }
            }
        }

事实上 我们分析的入口依然是refresh这个核心方法,这里就不重复贴源码了,这是我们之前loadBeanDefinitions换成 AnnotationConfigWebApplicationContext 类

20191102100628\_1.png

AnnotationBeanDefinitionReader 对应构造函数 为:

    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
            Assert.notNull(environment, "Environment must not be null");
            this.registry = registry;
            this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }

可以看到 最后一行 注册AnnotationConfigProcessors,有什么用呢,接着看其实现:

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
                BeanDefinitionRegistry registry, Object source) {

            DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
            if (beanFactory != null) {
                if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                    beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
                }
                if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                    beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
                }
            }

            Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
                    // 处理Configuration注解的 postProcessor
            if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
                    // 处理autowired注解的  postProcessor
            if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
                    // 处理required注解的 postProcessor
            if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
            }

            // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
            if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
            }

            // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
            if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition();
                try {
                    def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                            AnnotationConfigUtils.class.getClassLoader()));
                }
                catch (ClassNotFoundException ex) {
                    throw new IllegalStateException(
                            "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
                }
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
            }

            if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
            }
            if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
            }

            return beanDefs;
        }

这里我们只用关系,configuration注解的处理,实际是向容器中接入了 对Configuration注解的 处理类 ConfigurationClassPostProcessor,

那我们有个疑问,这个类什么时候会调用呢? 回到refresh方法中,有一行关键代码

    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);

方法内容比较多,这里就选取一个分支来说明下

    String[] postProcessorNames =
          beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

    // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
    List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
    for (String ppName : postProcessorNames) {
       if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
          priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
          processedBeans.add(ppName);
       }
    }
    sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
    registryPostProcessors.addAll(priorityOrderedPostProcessors);
    invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);

第一行:从工厂类中得到所有 BeanDefinitionRegistryPostProcessor类型的bean

第三——九行 循环判断添加到 需要处理的列表中

第十二行:执行具体需要处理的postProcessors

具体实现如下:

    private static void invokeBeanDefinitionRegistryPostProcessors(
          Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

       for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
          postProcessor.postProcessBeanDefinitionRegistry(registry);
       }
    }

也就是循环调用postProcessor的 postProcessBeanDefinitionRegistry方法,而ConfigurationClassPostProcessor类的对应方法内部调用逻辑顺序

postProcessBeanDefinitionRegistry ——》 processConfigBeanDefinitions ——》

    // Parse each @Configuration class
    ConfigurationClassParser parser = new ConfigurationClassParser(
          this.metadataReaderFactory, this.problemReporter, this.environment,
          this.resourceLoader, this.componentScanBeanNameGenerator, registry);

    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
    Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
    do {
       parser.parse(candidates);
       parser.validate();
       ....
    }while (!candidates.isEmpty());

从源码注释就能看出 是解析 @Configuration 注解的类 通过ConfigurationClassParser 来进行处理

parser ——》processConfigurationClass ——》doProcessConfigurationClass

    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
            // 递归处理成员类
            processMemberClasses(configClass, sourceClass);

            // 处理 @PropertySource 注解
            for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                    sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
                if (this.environment instanceof ConfigurableEnvironment) {
                    processPropertySource(propertySource);
                }
                else {
                    logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                            "]. Reason: Environment must implement ConfigurableEnvironment");
                }
            }

            // 处理 @ComponentScan 注解
            AnnotationAttributes componentScan = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ComponentScan.class);
            if (componentScan != null && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // Check the set of scanned definitions for any further config classes and parse recursively if necessary
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
                        parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
                    }
                }
            }

            // 处理 @Import 注解
            processImports(configClass, sourceClass, getImports(sourceClass), true);

            // 处理 @ImportResource 注解
            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);
                }
            }

            // 处理 @Bean 注解
            Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata methodMetadata : beanMethods) {
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
            }

            // 处理接口中默认方法
            for (SourceClass ifc : sourceClass.getInterfaces()) {
                beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
                for (MethodMetadata methodMetadata : beanMethods) {
                    if (!methodMetadata.isAbstract()) {
                        // A default method or other concrete method on a Java 8+ interface...
                        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
                    }
                }
            }

            // 处理父类
            if (sourceClass.getMetadata().hasSuperClass()) {
                String superclass = sourceClass.getMetadata().getSuperClassName();
                if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
                    this.knownSuperclasses.put(superclass, configClass);
                    // Superclass found, return its annotation metadata and recurse
                    return sourceClass.getSuperClass();
                }
            }

            // No superclass -> processing is complete
            return null;
        }

其他注解的处理这里暂且不作分析,后面有机会再补上,有兴趣的读者可以自行查看源码学习,原理都差不多,解析到对于的信息添加到configClass中

可以看到通过解析@Bean注解,获取到所有带有@Bean注解的方法,创建对应的BeanMethod添加到configClass中,回到processConfigBeanDefinitions方法

    this.reader.loadBeanDefinitions(configClasses);

通过configClasses加载bean定义

查看具体实现

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
       TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
       for (ConfigurationClass configClass : configurationModel) {
          loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
       }
    }

循环加载

    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);
       }
       // 循环加载 beanMethod
       for (BeanMethod beanMethod : configClass.getBeanMethods()) {
          loadBeanDefinitionsForBeanMethod(beanMethod);
       }
       loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
       loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

loadBeanDefinitionsForBeanMethod 字面意思 为beanMethod加载beanDefinition

    private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
       ConfigurationClass configClass = beanMethod.getConfigurationClass();
       MethodMetadata metadata = beanMethod.getMetadata();
       String methodName = metadata.getMethodName();

       // Do we need to mark the bean as skipped by its condition?
       if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
          configClass.skippedBeanMethods.add(methodName);
          return;
       }
       if (configClass.skippedBeanMethods.contains(methodName)) {
          return;
       }

       // Consider name and any aliases
       AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
       List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
       String beanName = (names.size() > 0 ? names.remove(0) : methodName);

       // Register aliases even when overridden
       for (String alias : names) {
          this.registry.registerAlias(beanName, alias);
       }

       // Has this effectively been overridden before (e.g. via XML)?
       if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
          return;
       }

       ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
       beanDef.setResource(configClass.getResource());
       beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

       if (metadata.isStatic()) {
          // static @Bean method
          beanDef.setBeanClassName(configClass.getMetadata().getClassName());
          beanDef.setFactoryMethodName(methodName);
       }
       else {
          // instance @Bean method
          beanDef.setFactoryBeanName(configClass.getBeanName());
          beanDef.setUniqueFactoryMethodName(methodName);
       }
       beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
       beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

       AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

       Autowire autowire = bean.getEnum("autowire");
       if (autowire.isAutowire()) {
          beanDef.setAutowireMode(autowire.value());
       }

       String initMethodName = bean.getString("initMethod");
       if (StringUtils.hasText(initMethodName)) {
          beanDef.setInitMethodName(initMethodName);
       }

       String destroyMethodName = bean.getString("destroyMethod");
       if (destroyMethodName != null) {
          beanDef.setDestroyMethodName(destroyMethodName);
       }

       // Consider scoping
       ScopedProxyMode proxyMode = ScopedProxyMode.NO;
       AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
       if (attributes != null) {
          beanDef.setScope(attributes.getAliasedString("value", Scope.class, configClass.getResource()));
          proxyMode = attributes.getEnum("proxyMode");
          if (proxyMode == ScopedProxyMode.DEFAULT) {
             proxyMode = ScopedProxyMode.NO;
          }
       }

       // Replace the original bean definition with the target one, if necessary
       BeanDefinition beanDefToRegister = beanDef;
       if (proxyMode != ScopedProxyMode.NO) {
          BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
                new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS);
          beanDefToRegister = new ConfigurationClassBeanDefinition(
                (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
       }

       if (logger.isDebugEnabled()) {
          logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
                configClass.getMetadata().getClassName(), beanName));
       }

       this.registry.registerBeanDefinition(beanName, beanDefToRegister);
    }

通过元数据以及相关信息 装配 注册beanDefinition


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » SPRING源码分析(四)之@Configuration @Bean的方式配置bean

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏