Spring-IOC(五)
作者:互联网
parser.validate
本来想把parse、validate、loadBeanDefinition三个在一篇文章中介绍完的,但发现介绍完parse方法之后就很长了,只能另起篇章
这个方法就比较简单了,主要是对@Configuration和@Bean注解的一些校验
- 校验@Configuration注解的类不能是final修饰,因为被该注解标注的类是需要进行CGLIB代理的
- 如果@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是否需要跳过
- 判断该configClass是否在importedBy集合中,如果存在,说明是一个内部类,需要对内部类进行处理,这里处理的是非静态内部类,静态内部类在doScan方法中处理过了
- 获取全部的@Bean注解的configClass进行处理
- 加载解析@ImportResource
- 加载解析@Import
处理内部类
如果该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 + "'");
}
}
这个方法就比较简单了:
- 获取configClass中的注解元数据
- 将注解元数据包装成AnnotatedGenericBeanDefinition类型
- 解析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了,那么还需要这个方法干嘛呢?这个方法主要做如下两件事:
- 针对含有@Configuration注解的类做特殊处理
- 增加后置处理器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);
}
}
}
- 查找出所有的含有@Configuration注解的beanDefinition,放入configBeanDefs集合中。这里查找的条件就是属性中是full的(full和lite在这里用上了)
- 如果configBeanDefs集合为空,说明没有@Configuration注解的bean definition,直接return
- 遍历configBeanDefs集合,设置属性AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE为true,代表着使用cglib代理增强
- 调用enhance方法惊醒增强
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