//最终调到AbstractApplicationContext的refresh方法publicvoidrefresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.// 1. 初始化前的预处理prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 2. 获取BeanFactory,加载所有bean的定义信息(未实例化)ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// 3. BeanFactory的预处理配置prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 4. 准备BeanFactory完成后进行的后置处理postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 5. 执行BeanFactory创建后的后置处理器invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 6. 注册Bean的后置处理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.// 7. 初始化MessageSourceinitMessageSource();// Initialize event multicaster for this context.// 8. 初始化事件派发器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 9. 子类的多态onRefreshonRefresh();// Check for listener beans and register them.// 10. 注册监听器registerListeners();//到此为止,BeanFactory已创建完成// Instantiate all remaining (non-lazy-init) singletons.// 11. 初始化所有剩下的单例BeanfinishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.// 12. 完成容器的创建工作finishRefresh(); }catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - "+"cancelling refresh attempt: "+ ex); }// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex; }finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...// 13. 清除缓存resetCommonCaches(); } }}
这个方法非常长,一共有13个步骤,本篇我们来看前3个步骤:
publicvoidrefresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.// 1. 初始化前的预处理prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 2. 获取BeanFactory,加载所有bean的定义信息(未实例化)ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// 3. BeanFactory的预处理配置prepareBeanFactory(beanFactory);
1. prepareRefresh:初始化前的预处理
protectedvoidprepareRefresh() {this.startupDate=System.currentTimeMillis(); // 记录启动时间this.closed.set(false); // 标记IOC容器的关闭状态为falsethis.active.set(true); // 标记IOC容器已激活if (logger.isInfoEnabled()) {logger.info("Refreshing "+this); }// Initialize any placeholder property sources in the context environment// 1.1 初始化属性配置initPropertySources();// Validate that all properties marked as required are resolvable// see ConfigurablePropertyResolver#setRequiredProperties// 1.2 属性校验getEnvironment().validateRequiredProperties();// Allow for the collection of early ApplicationEvents,// to be published once the multicaster is available...// 这个集合的作用,是保存容器中的一些事件,以便在合适的时候利用事件广播器来广播这些事件// 【配合registerListeners方法中的第三部分使用】this.earlyApplicationEvents=newLinkedHashSet<>();}
最前面先记录启动时间,标记IOC容器状态,之后要开始初始化属性配置:
1.1 initPropertySources:初始化属性配置
protectedvoidinitPropertySources() {// For subclasses: do nothing by default.}
publicstaticfinalString SERVLET_CONTEXT_PROPERTY_SOURCE_NAME ="servletContextInitParams";publicstaticfinalString SERVLET_CONFIG_PROPERTY_SOURCE_NAME ="servletConfigInitParams";publicstaticvoidinitServletPropertySources(MutablePropertySources sources, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
Assert.notNull(sources,"'propertySources' must not be null");String name =StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;if (servletContext !=null&&sources.contains(name) &&sources.get(name) instanceof StubPropertySource) {sources.replace(name,new ServletContextPropertySource(name, servletContext)); } name =StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;if (servletConfig !=null&&sources.contains(name) &&sources.get(name) instanceof StubPropertySource) {sources.replace(name,new ServletConfigPropertySource(name, servletConfig)); }}
这个方法的文档注释:
Replace Servlet-based stub property sources with actual instances populated with the given servletContext and servletConfig objects. This method is idempotent with respect to the fact it may be called any number of times but will perform replacement of stub property sources with their corresponding actual property sources once and only once.
initPropertySources();// Validate that all properties marked as required are resolvable// see ConfigurablePropertyResolver#setRequiredProperties// 1.2 属性校验getEnvironment().validateRequiredProperties();
getEnvironment().validateRequiredProperties();// Allow for the collection of early ApplicationEvents,// to be published once the multicaster is available...// 这个集合的作用,是保存容器中的一些事件,以便在合适的时候利用事件广播器来广播这些事件// 【配合registerListeners方法中的第三部分使用】this.earlyApplicationEvents=newLinkedHashSet<>();
protectedfinalvoidrefreshBeanFactory() throws IllegalStateException {if (!this.refreshed.compareAndSet(false,true)) {thrownewIllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); }this.beanFactory.setSerializationId(getId());}
protectedfinalvoidrefreshBeanFactory() throws BeansException {if (hasBeanFactory()) {destroyBeans();closeBeanFactory(); }try {// 创建BeanFactoryDefaultListableBeanFactory beanFactory =createBeanFactory();beanFactory.setSerializationId(getId());// 自定义配置BeanFactorycustomizeBeanFactory(beanFactory);// 解析、加载XML中定义的BeanDefinitionloadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory= beanFactory; } }catch (IOException ex) {thrownewApplicationContextException("I/O error parsing bean definition source for "+ getDisplayName(), ex); }}protectedDefaultListableBeanFactorycreateBeanFactory() {returnnewDefaultListableBeanFactory(getInternalParentBeanFactory());}// 使用XmlBeanDefinitionReader做bean的装配(即解析xml)protectedvoidloadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReader beanDefinitionReader =newXmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader);loadBeanDefinitions(beanDefinitionReader);}
protectedvoidprepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.// 设置BeanFactory的类加载器、表达式解析器等beanFactory.setBeanClassLoader(getClassLoader());beanFactory.setBeanExpressionResolver(newStandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));beanFactory.addPropertyEditorRegistrar(newResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.// 3.1 配置一个可回调注入ApplicationContext的BeanPostProcessorbeanFactory.addBeanPostProcessor(newApplicationContextAwareProcessor(this));beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);// BeanFactory interface not registered as resolvable type in a plain factory.// MessageSource registered (and found for autowiring) as a bean.// 3.2 自动注入的支持beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class,this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class,this);beanFactory.registerResolvableDependency(ApplicationContext.class,this);// Register early post-processor for detecting inner beans as ApplicationListeners.// 3.3 配置一个可加载所有监听器的组件beanFactory.addBeanPostProcessor(newApplicationListenerDetector(this));// Detect a LoadTimeWeaver and prepare for weaving, if found.if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(newLoadTimeWeaverAwareProcessor(beanFactory));// Set a temporary ClassLoader for type matching.beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }// Register default environment beans.// 注册了默认的运行时环境、系统配置属性、系统环境的信息if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME,getEnvironment()); }if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME,getEnvironment().getSystemProperties()); }if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME,getEnvironment().getSystemEnvironment()); }}
Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies. ApplicationContexts can autodetect BeanPostProcessor beans in their bean definitions and apply them to any beans subsequently created. Plain bean factories allow for programmatic registration of post-processors, applying to all beans created through this factory. Typically, post-processors that populate beans via marker interfaces or the like will implement postProcessBeforeInitialization, while post-processors that wrap beans with proxies will normally implement postProcessAfterInitialization.
The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization. This method MUST be invoked before the class is put into service. This annotation MUST be supported on all classes that support dependency injection.
Interface to be implemented by beans that need to react once all their properties have been set by a BeanFactory: e.g. to perform custom initialization, or merely to check that all mandatory properties have been set. An alternative to implementing InitializingBean is specifying a custom init method, for example in an XML bean definition.
Apply this BeanPostProcessor to the given new bean instance before any bean initialization callbacks (like InitializingBean's afterPropertiesSet or a custom init-method). The bean will already be populated with property values. The returned bean instance may be a wrapper around the original.
Apply this BeanPostProcessor to the given new bean instance after any bean initialization callbacks (like InitializingBean's afterPropertiesSet or a custom init-method). The bean will already be populated with property values. The returned bean instance may be a wrapper around the original.
// Configure the bean factory with context callbacks.// 3.1 配置一个可回调注入ApplicationContext的BeanPostProcessorbeanFactory.addBeanPostProcessor(newApplicationContextAwareProcessor(this));beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
BeanPostProcessor implementation that passes the ApplicationContext to beans that implement the EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware and/or ApplicationContextAware interfaces. Implemented interfaces are satisfied in order of their mention above. Application contexts will automatically register this with their underlying bean factory. Applications do not use this directly.
// BeanFactory interface not registered as resolvable type in a plain factory.// MessageSource registered (and found for autowiring) as a bean.beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);
上面的单行注释翻译:
BeanFactory 接口未在普通工厂中注册为可解析类型。
MessageSource 注册为Bean(并发现用于自动装配)。
上面一句还能看懂,下面是干什么?讲真我也不是很清楚,咱还是看看这个方法的文档注释吧。
Register a special dependency type with corresponding autowired value. This is intended for factory/context references that are supposed to be autowirable but are not defined as beans in the factory: e.g. a dependency of type ApplicationContext resolved to the ApplicationContext instance that the bean is living in. Note: There are no such default types registered in a plain BeanFactory, not even for the BeanFactory interface itself.
/** Map from dependency type to corresponding autowired value. */private final Map<Class<?>, Object> resolvableDependencies =new ConcurrentHashMap<>(16);public voidregisterResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) { Assert.notNull(dependencyType,"Dependency type must not be null"); if (autowiredValue != null) { if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) { throw new IllegalArgumentException("Value [" + autowiredValue +"] does not implement specified dependency type [" + dependencyType.getName() + "]"); } this.resolvableDependencies.put(dependencyType, autowiredValue); }}
// Register early post-processor for detecting inner beans as ApplicationListeners.beanFactory.addBeanPostProcessor(newApplicationListenerDetector(this));
又注册了一个后置处理器,来看 ApplicationListenerDetector 的文档注释:
BeanPostProcessor that detects beans which implement the ApplicationListener interface. This catches beans that can't reliably be detected by getBeanNamesForType and related operations which only work against top-level beans.
publicObjectpostProcessAfterInitialization(Object bean,String beanName) {if (bean instanceof ApplicationListener) {// potentially not detected as a listener by getBeanNamesForType retrievalBoolean flag =this.singletonNames.get(beanName);if (Boolean.TRUE.equals(flag)) {// singleton bean (top-level or inner): register on the flythis.applicationContext.addApplicationListener((ApplicationListener<?>) bean); }elseif (Boolean.FALSE.equals(flag)) {if (logger.isWarnEnabled() &&!this.applicationContext.containsBean(beanName)) {// inner bean with other scope - can't reliably process eventslogger.warn("Inner bean '"+ beanName +"' implements ApplicationListener interface "+"but is not reachable for event multicasting by its containing ApplicationContext "+"because it does not have singleton scope. Only top-level listener beans are allowed "+"to be of non-singleton scope."); }this.singletonNames.remove(beanName); } }return bean;}
Variant of ServletContextAwareProcessor for use with a ConfigurableWebApplicationContext. Can be used when registering the processor can occur before the ServletContext or ServletConfig have been initialized.
BeanPostProcessor implementation that passes the ServletContext to beans that implement the ServletContextAware interface. Web application contexts will automatically register this with their underlying bean factory. Applications do not use this directly.
// ClassPathScanningCandidateComponentProviderprotectedStringresolveBasePackage(String basePackage) {returnClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage));}// ClassUtilsprivatestaticfinalchar PACKAGE_SEPARATOR ='.';privatestaticfinalchar PATH_SEPARATOR ='/';publicstaticStringconvertClassNameToResourcePath(String className) {Assert.notNull(className,"Class name must not be null");returnclassName.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);}
String CLASSPATH_ALL_URL_PREFIX ="classpath*:";publicResource[] getResources(String locationPattern) throws IOException {Assert.notNull(locationPattern,"Location pattern must not be null");if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {// a class path resource (multiple resources for same name possible)if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {// a class path resource patternreturnfindPathMatchingResources(locationPattern); }else {// all class path resources with the given namereturnfindAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); } }else {// Generally only look for a pattern after a prefix here,// and on Tomcat only after the "*/" separator for its "war:" protocol.int prefixEnd = (locationPattern.startsWith("war:") ?locationPattern.indexOf("*/") +1:locationPattern.indexOf(':') +1);if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {// a file patternreturnfindPathMatchingResources(locationPattern); }else {// a single resource with the given namereturnnewResource[] {getResourceLoader().getResource(locationPattern)}; } }}
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
// a class path resource (multiple resources for same name possible)
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// a class path resource pattern
return findPathMatchingResources(locationPattern);
}
else {
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
// all class path resources with the given name
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
// ...
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
Set<Resource> result = new LinkedHashSet<>(16);
ClassLoader cl = getClassLoader();
Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
while (resourceUrls.hasMoreElements()) {
URL url = resourceUrls.nextElement();
result.add(convertClassLoaderURL(url));
}
if ("".equals(path)) {
// The above result is likely to be incomplete, i.e. only containing file system references.
// We need to have pointers to each of the jar files on the classpath as well...
addAllClassLoaderJarRoots(cl, result);
}
return result;
}
Check the given candidate's bean name, determining whether the corresponding bean definition needs to be registered or conflicts with an existing definition.
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 5.1 执行BeanFactory后置处理器
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* 在应用程序上下文的标准初始化之后修改其内部bean工厂。
* 所有bean定义都已经加载,但是还没有实例化bean。这允许覆盖或添加属性,甚至可以初始化bean。
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* 在标准初始化之后修改应用程序上下文的内部bean定义注册表。
* 所有常规bean定义都已加载,但还没有实例化bean。
* 这允许在下一个后期处理阶段开始之前添加进一步的bean定义。
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
BeanFactoryPostProcessor used for bootstrapping processing of @Configuration classes. Registered by default when using <context:annotation-config/> or <context:component-scan/>. Otherwise, may be declared manually as with any other BeanFactoryPostProcessor. This post processor is priority-ordered as it is important that any Bean methods declared in @Configuration classes have their corresponding bean definitions registered before any other BeanFactoryPostProcessor executes.
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
// ......
if (isFullConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (isLiteConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// 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 needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}