其他分享
首页 > 其他分享> > Spring-IOC(五)

Spring-IOC(五)

作者:互联网

parser.validate

本来想把parse、validate、loadBeanDefinition三个在一篇文章中介绍完的,但发现介绍完parse方法之后就很长了,只能另起篇章
这个方法就比较简单了,主要是对@Configuration和@Bean注解的一些校验

  1. 校验@Configuration注解的类不能是final修饰,因为被该注解标注的类是需要进行CGLIB代理的
  2. 如果@Bean注解所在的类页游@Configuration注解标注,那么该方法是可以被重写的,否则抛出异常
public void validate() {
    for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
        configClass.validate(this.problemReporter);
    }
}

public void validate(ProblemReporter problemReporter) {
    // A configuration class may not be final (CGLIB limitation)
    if (getMetadata().isAnnotated(Configuration.class.getName())) {
        if (getMetadata().isFinal()) {
            problemReporter.error(new FinalConfigurationProblem());
        }
    }

    for (BeanMethod beanMethod : this.beanMethods) {
        beanMethod.validate(problemReporter);
    }
}

public void validate(ProblemReporter problemReporter) {
    if (getMetadata().isStatic()) {
        // static @Bean methods have no constraints to validate -> return immediately
        return;
    }

    if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
        if (!getMetadata().isOverridable()) {
            // instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
            problemReporter.error(new NonOverridableMethodError());
        }
    }
}

loadBeanDefinitions

该步骤就是对之前没有加入到beanDefinitionMap中的对象进行处理,@Bean,@Configuration,@Import,@ImportResource,@ImportRegistry注册为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.removeImportingClass(configClass.getMetadata().getClassName());
        return;
    }

    if (configClass.isImported()) {
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }

    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }

    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

处理内部类
如果该configClass中的importedBy集合有数据,那么就需要处理该内部类,将该内部类变成beanDefinition。这里需要说明一下为什么内部类会存在importBy这个集合中:在处理@Component注解的时候需要处理内部类,在processMemberClasses方法中如果发现了内部类,就会将该外部类放入importStack中并调用processConfigurationClass方法对内部类进行处理,对内部类的注解进行处理。在调用processConfigurationClass方法传递的参数是candidate.asConfigClass(configClass),在这个方法中就会将configClass加入到importBy集合中。还有一个地方就是在@Import注解的时候如果该类是个普通类,那么也会在这里处理

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
    AnnotationMetadata metadata = configClass.getMetadata();
    AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

    ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
    configBeanDef.setScope(scopeMetadata.getScopeName());
    String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
    AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
    configClass.setBeanName(configBeanName);

    if (logger.isTraceEnabled()) {
        logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
    }
}

这个方法就比较简单了:

  1. 获取configClass中的注解元数据
  2. 将注解元数据包装成AnnotatedGenericBeanDefinition类型
  3. 解析scope
    4.处理通用注解,这个之前说过,比如@Lazy、@Primary、@DependsOn、@Role、@Description
    5.包装成BeanDefinitionHolder对象类型
    6.注册到beanDefinitionMap中

处理@Bean注解
这个方法中就是处理@Bean注解,这个方法比上个较为复杂,把主要步骤放在方法里的注释

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
	// 获取ConfigurationClass
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
	// 获取注解元数据
    MethodMetadata metadata = beanMethod.getMetadata();
	// 获取方法名
    String methodName = metadata.getMethodName();

    // Do we need to mark the bean as skipped by its condition?
	// 判断方法上的@Conditional注解,判断是否需要跳过
    if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
        configClass.skippedBeanMethods.add(methodName);
        return;
    }
    if (configClass.skippedBeanMethods.contains(methodName)) {
        return;
    }

	// 获取@Bean注解上的属性
    AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
    Assert.state(bean != null, "No @Bean annotation attributes");

    // Consider name and any aliases
	// 获取这些属性名--name
    List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
	// beanName,如果names不为null就使用name属性的第一个值作为beanName,其他那么属性值作为别名
    String beanName = (!names.isEmpty() ? 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)?
	// 判断是否存在和该beanName相同的已经存在的bean,如果已经存在,是否允许覆盖
    if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
        if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
            throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
                    beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
                    "' clashes with bean name for containing configuration class; please make those names unique!");
        }
        return;
    }
	// 将configClass转换为ConfigurationClassBeanDefinition
    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
    beanDef.setResource(configClass.getResource());
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

	// 如果该bean标注的方法是静态的
    if (metadata.isStatic()) {
        // static @Bean method
		// 设置静态工厂,记住这里设置了factoryMethodName属性
        beanDef.setBeanClassName(configClass.getMetadata().getClassName());
        beanDef.setFactoryMethodName(methodName);
    }
    else {
        // instance @Bean method
		// 看做实例工厂,记住这里设置了factoryMethodName属性
        beanDef.setFactoryBeanName(configClass.getBeanName());
        beanDef.setUniqueFactoryMethodName(methodName);
    }
	// 设置自动注入属性,默认是构造方法注入
    beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
	// 这是属性
 beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
            SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

	// 处理通用注解@Lazy、@Primary、@DependsOn、@Role、@Description
    AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
	// 设置autowire属性,默认是Autowire.NO--不自动注入
    Autowire autowire = bean.getEnum("autowire");
    if (autowire.isAutowire()) {
        beanDef.setAutowireMode(autowire.value());
    }
	// 获取@Bean注解中的autowireCandidate属性值,默认为true
    boolean autowireCandidate = bean.getBoolean("autowireCandidate");
    if (!autowireCandidate) {
        beanDef.setAutowireCandidate(false);
    }
	// 设置@Bean注解中的initMethod属性值
    String initMethodName = bean.getString("initMethod");
    if (StringUtils.hasText(initMethodName)) {
        beanDef.setInitMethodName(initMethodName);
    }
	// 设置@Bean注解中的destroyMethod属性值
    String destroyMethodName = bean.getString("destroyMethod");
    beanDef.setDestroyMethodName(destroyMethodName);

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

    // Replace the original bean definition with the target one, if necessary
	// 如有必要将原始bean definition 替换为目标代理
    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.isTraceEnabled()) {
        logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
                configClass.getMetadata().getClassName(), beanName));
    }
	// 注册到beanDefinitionMap中
    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

处理@ImportResource注解
loadBeanDefinitionsFromImportedResources这个方法就是加载解析@ImportResource注解引入的XML配置文件中的bean定义到注册表中

处理@Import注解
在之前的ConfigurationClassParser#doProcessConfigurationClass方法中解析到了@Import注解,只会将对应的对象存储起来,并不会转换成beanDefinition,是在这里进行处理的

之前说过在使用@Import注解的时候,value属性值只有三种情况:要么实现ImportSelector,要么实现ImportBeanDefinitionRegistrar,要么是一个普通类。其中ImportSelector的selectImports方法返回的是一个数组,数组中存的是类路径地址,返回的这些类可能会被注册为beanDefinition;如果是一个普通类的话,那么就会在loadBeanDefinitionsForConfigurationClass方法中的if(configClass.isImported())这个条件中执行,将这个普通类变成一个bean definition;如果实现的是ImportBeanDefinitionRegistrar,那么就会在loadBeanDefinitionsFromRegistrars方法中回调ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法,在registerBeanDefinitions方法可能会有将一个对象转成bean definition

	private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry));
	}

到现在就算是把parse、validate、loadBeanDefinitions三个方法介绍完毕了。这三个方法介绍完毕,ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry方法也就介绍完毕了,那么PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法中的invokeBeanDefinitionRegistryPostProcessors这个步骤介绍完毕了,根据之前文章该方法的步骤还剩下一个重要的节点:invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors

该方法是BeanFactoryPostProcessor接口的方法,ConfigurationClassPostProcessor间接实现了BeanFactoryPostProcessor,那么也就会执行invokeBeanFactoryPostProcessor方法,接下来看看ConfigurationClassPostProcessor#invokeBeanFactoryPostProcessor做了哪些功能

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    int factoryId = System.identityHashCode(beanFactory);
    if (this.factoriesPostProcessed.contains(factoryId)) {
        throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + beanFactory);
    }
    this.factoriesPostProcessed.add(factoryId);
    if (!this.registriesPostProcessed.contains(factoryId)) {
        // BeanDefinitionRegistryPostProcessor hook apparently not supported...
        // Simply call processConfigurationClasses lazily at this point then.
        processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    }

    enhanceConfigurationClasses(beanFactory);
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

在postProcessBeanDefinitionRegistry方法中已经将符合规则的class扫描出来并变成bean definition了,那么还需要这个方法干嘛呢?这个方法主要做如下两件事:

  1. 针对含有@Configuration注解的类做特殊处理
  2. 增加后置处理器ImportAwareBeanPostProcessor

含有@Configuration注解的类做特殊处理

这个主要是对@Bean和@Configuration注解及其派生注解标注的配置类内部的setBeanFactory的方法做增强。

在使用spring的@Bean这个注解的时候,我们一般都会在类上加@Configuration注解,但有时候也会使用@Component注解,那么这两个注解有什么不同呢?
如果被注解@Bean的方法之间没有互相调用的话,那么使用@Configuration和@Component都是一样的。如果是有互相调用的情况的话,那么就只能使用@Configuration注解,否则不生效。因为使用@Configuration注解的类会被代理增强,对@Bean和BeanFactoryAware#setBeanFactory进行增强

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        // 判断是否含有@Configuration注解
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
            if (!(beanDef instanceof AbstractBeanDefinition)) {
                throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                        beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
            }
            else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                logger.info("Cannot enhance @Configuration bean definition '" + beanName +
                        "' since its singleton instance has been created too early. The typical cause " +
                        "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                        "return type: Consider declaring such methods as 'static'.");
            }
            configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
        }
    }
    if (configBeanDefs.isEmpty()) {
        // nothing to enhance -> return immediately
        return;
    }

    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        // If a @Configuration class gets proxied, always proxy the target class
        // 对于配置类永远使用cglib代理
        beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        try {
            // Set enhanced subclass of the user-specified bean class
            Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
            if (configClass != null) {

                Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
                if (configClass != enhancedClass) {
                    if (logger.isTraceEnabled()) {
                        logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                                "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
                    }
                    beanDef.setBeanClass(enhancedClass);
                }
            }
        }
        catch (Throwable ex) {
            throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
        }
    }
}

enhance

public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
    if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Ignoring request to enhance %s as it has " +
                    "already been enhanced. This usually indicates that more than one " +
                    "ConfigurationClassPostProcessor has been registered (e.g. via " +
                    "<context:annotation-config>). This is harmless, but you may " +
                    "want check your configuration and remove one CCPP if possible",
                    configClass.getName()));
        }
        return configClass;
    }
    Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
    if (logger.isTraceEnabled()) {
        logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
                configClass.getName(), enhancedClass.getName()));
    }
    return enhancedClass;
}

上面这个方法就是增强的方法,主要看createClass和newEnhancer这两个方法
newEnhancer
构建Enhancer对象,说明使用的是cglib代理

private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(configSuperClass);
    enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
    enhancer.setUseFactory(false);
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
    enhancer.setCallbackFilter(CALLBACK_FILTER);
    enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
    return enhancer;
}

从上面代码可以看出代理类设置的父类为目标类,还实现了一个接口EnhancedConfiguration,设置回调类型

createClass
将创建好的Enhancer传递给createClass方法


private static final Callback[] CALLBACKS = new Callback[] {
        // 拦截 @Bean 注解的方法,以确保正确处理 @Bean
        new BeanMethodInterceptor(),
        // 拦截 BeanFactoryAware#setBeanFactory 的调用
        new BeanFactoryAwareMethodInterceptor(),
        NoOp.INSTANCE
};

private Class<?> createClass(Enhancer enhancer) {
    Class<?> subclass = enhancer.createClass();
    // Registering callbacks statically (as opposed to thread-local)
    // is critical for usage in an OSGi environment (SPR-5932)...
    Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
    return subclass;
}

从上面的代码可以看出设置的回调是CALLBACKS

BeanMethodInterceptor

该类是拦截@Bean注解,这个类实现了MethodInterceptor,这个MethodInterceptor是cglib中的类,调用@Bean注解对应的方法时会先调用intercept方法

public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
            MethodProxy cglibMethodProxy) throws Throwable {

    // 调用getBeanFactory方法获取beanFactory,实际上代理类生成了一个"$$beanFactory"属性,用于存放beanFactory。
    ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
    // 该方法会默认将方法名作为beanName,,如果指定了@Bean注解的name属性,那么将会取第一个值作为beanName。
    String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

    // Determine whether this bean is a scoped-proxy
    if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
        String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
        if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
            beanName = scopedBeanName;
        }
    }

    // To handle the case of an inter-bean method reference, we must explicitly check the
    // container for already cached instances.

    // First, check to see if the requested bean is a FactoryBean. If so, create a subclass
    // proxy that intercepts calls to getObject() and returns any cached bean instance.
    // This ensures that the semantics of calling a FactoryBean from within @Bean methods
    // is the same as that of referring to a FactoryBean within XML. See SPR-6602.
    // 检查容器中是否存在 FactoryBean,如果存在则创建一个增强类
    // 通过创建增强类来拦截 getObject 方法,以确保 FactoryBean 的语义
    // 检查当前beanName对应的bean实例或者定义存在,并且是FactoryBean类型,第一次调用的时候应该是不存在的。如果存在就返回一个FactoryBean代理对象。
    if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
            factoryContainsBean(beanFactory, beanName)) {
        //获取factoryBean实例本身
        Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
        //创建一个FactoryBean的增强类来拦截getObject方法
        if (factoryBean instanceof ScopedProxyFactoryBean) {
            // Scoped proxy factory beans are a special case and should not be further proxied
        }
        else {
            // It is a candidate FactoryBean - go ahead with enhancement
            // 这里将会选择合适的代理方式,JDK的代理或者CGLIB的代理
            return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
        }
    }

    // 判断当时执行的方法是否是 @Bean 方法本身
    // 举个例子 : 如果是直接调用@Bean方法,也就是Spring来调用我们的@Bean方法,则返回true
    // 如果是在别的方法内部,我们自己的程序调用 @Bean方法,则返回false
    /*
        isCurrentlyInvokedFactoryMethod方法用于检查给定方法是否对应于容器当前调用的方法,
        仅比较方法名称和参数类型。也就是说,如果@Bean方法是Spring自动调用的,比如用于创建对象,
        那么返回true,如果在其他@Bean方法中被调用,那么返回false。
        */
    if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
        // The factory is calling the bean method in order to instantiate and register the bean
        // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
        // create the bean instance.
        if (logger.isInfoEnabled() &&
                BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
            logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
                            "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
                            "result in a failure to process annotations such as @Autowired, " +
                            "@Resource and @PostConstruct within the method's declaring " +
                            "@Configuration class. Add the 'static' modifier to this method to avoid " +
                            "these container lifecycle issues; see @Bean javadoc for complete details.",
                    beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
        }
        // 如果是Spring自动调用的该@Bean方法,那么调用invokeSuper方法,实际上就是调用当前@Bean方法本身,用于创建bean实例,没有任何增强,返回对应的结果。
        return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
    }

    // 否则,则尝试从容器中获取该 Bean 对象
    // 怎么获取呢? 通过调用 beanFactory.getBean 方法
    // 而这个getBean 方法,如果对象已经创建则直接返回,如果还没有创建,则创建,然后放入容器中,然后返回
    /*
     * 如果当前@Bean方法是在其他@Bean方法中被调用的。那么调用resolveBeanReference尝试直接从容器中获取给定BeanName的对象,
     * 如果容器中有,就直接返回,该@Bean方法后续不再被调用;如果没有,那么创建,该@Bean方法被调用一次,后续不再被调用。其核心就是beanFactory.getBean方法。
     */
    return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

/**
 *
 * 如果当前@Bean方法是在其他@Bean方法中被调用,或者是外部对象对@Bean方法的调用(这要求该对象交给Spring容器管理),
 * 那么直接从容器中获取给定BeanName的对象,如果容器中有,就直接返回,该@Bean方法后续不再被调用。如果没有,那么创建,该@Bean方法被调用一次,后续不再被调用。
 *
 * 核心方法就是IoC容器初始化的finishBeanFactoryInitialization阶段beanFactory.getBean方法(该方法我们在),
 * 如果有缓存,就从缓存取,没有就创建。创建的方法,在getBean方法内部的createBeanInstance方法中,
 * 将会通过工厂方法创建bean实例,即调用instantiateUsingFactoryMethod方法获取实例。IoC容器初始化我们在前面的文章就讲过了。
 *
 * 如果@Bean方法之间存在互相调用,可以是间接的通过其他外部对象(这要求该对象交给Spring容器管理)调用,那么表示它们存在依赖关系,
 * 将会通过registerDependentBean方法注册到容器中,如果仅仅是外部对象(这要求该对象交给Spring容器管理)调用@Bean方法,那么不会注册依赖关系。
 *
 * @param beanMethod
 * @param beanMethodArgs
 * @param beanFactory
 * @param beanName
 * @return
 */
private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
        ConfigurableBeanFactory beanFactory, String beanName) {

    // The user (i.e. not the factory) is requesting this bean through a call to
    // the bean method, direct or indirect. The bean may have already been marked
    // as 'in creation' in certain autowiring scenarios; if so, temporarily set
    // the in-creation status to false in order to avoid an exception.
    //当前bean是否在创建中
    boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
    try {
        if (alreadyInCreation) {
            //设置为非创建状态
            beanFactory.setCurrentlyInCreation(beanName, false);
        }
        //判断是否需要使用参数
        boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
        //如果需要使用参数并且当前beanName对应的bean是单例的
        if (useArgs && beanFactory.isSingleton(beanName)) {
            // Stubbed null arguments just for reference purposes,
            // expecting them to be autowired for regular singleton references?
            // A safe assumption since @Bean singleton arguments cannot be optional...
            for (Object arg : beanMethodArgs) {
                //如果有一个参数为null,那么useArgs设置为false,@Bean单例对象的参数不是可选的
                if (arg == null) {
                    useArgs = false;
                    break;
                }
            }
        }
        //调用beanFactory.getBean方法获取bean实例,这一步就是从缓存中获取,如果没有,那么就创建,创建的时候就会调用那个该@Bean方法
        //如果有就直接返回,不再调用该@Bean方法
        Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
                beanFactory.getBean(beanName));
        //是否等于给定类型,一般都不相等,除了字符串类型
        if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
            // Detect package-protected NullBean instance through equals(null) check
            //这里的equals是为了检测NullBean实例
            if (beanInstance.equals(null)) {
                if (logger.isDebugEnabled()) {
                    logger.debug(String.format("@Bean method %s.%s called as bean reference " +
                            "for type [%s] returned null bean; resolving to null value.",
                            beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                            beanMethod.getReturnType().getName()));
                }
                //如果是NullBean,那么设置为null
                beanInstance = null;
            }
            else {
                String msg = String.format("@Bean method %s.%s called as bean reference " +
                        "for type [%s] but overridden by non-compatible bean instance of type [%s].",
                        beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                        beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
                try {
                    BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
                    msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
                }
                catch (NoSuchBeanDefinitionException ex) {
                    // Ignore - simply no detailed message then.
                }
                throw new IllegalStateException(msg);
            }
        }
        //获取当前最外层正在被调用的@Bean方法,也就是直接或者间接调用该@Bean方法的@Bean方法,因此可能为null
        Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
        if (currentlyInvoked != null) {
            //获取外部@Bean方法的beanName
            String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
            //注册外部@Bean方法和内部@Bean方法的依赖关系
            beanFactory.registerDependentBean(beanName, outerBeanName);
        }
        return beanInstance;
    }
    finally {
        if (alreadyInCreation) {
            beanFactory.setCurrentlyInCreation(beanName, true);
        }
    }
}

添加后置处理器:ImportAwareBeanPostProcessor

这个后置处理器就是为了支持配置类代理对象的创建,这个processor是在后续属性填充阶段调用的,后面会有详细的介绍

到这里ConfigurationClassPostProcessor这个类就介绍完了,那么refresh方法中的第五步:invokeBeanFactoryPostProcessors就说完了。后面会有专门一篇文章介绍BeanFactoryPostProcessor接口的作用以及@Configuration注解的使用

标签:configClass,Spring,beanName,bean,方法,Bean,注解,IOC
来源: https://www.cnblogs.com/yashon/p/15054683.html