ClassPathXmlApplicationContext source code (2) - BeanFactory initialization, loading, registration process

Overview of this article

How to initialize the context and parse the resource path above mainly introduces the super(parent) and setConfigLocations(configLocations) methods, and then mainly introduces the prepareRefresh() and obtainFreshBeanFactory() methods in the container initialization refresh function.

	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
    
    

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
    
    
			refresh();
		}
	}

source code

refresh()

The refresh method is responsible for completing the initialization of the entire container. There are many methods below, and we will follow up step by step.

	@Override
	public void refresh() throws BeansException, IllegalStateException {
    
    
		synchronized (this.startupShutdownMonitor) {
    
       //保证同一时刻只有一个线程在初始化
			// 为refresh做准备:设置启动时间,设置active标记,验证require的标记的属性是否可解析
			prepareRefresh();

			// 对上下文的底层bean工厂执行一次实际的刷新,关闭之前的bean工厂(如果有的话),并为上下文生命周期的下一阶段初始化一个新bean工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 准备上下文的bean工厂
			prepareBeanFactory(beanFactory);

			try {
    
    
				// 允许在子类的上下文中预处理bean工厂
				postProcessBeanFactory(beanFactory);

				// 执行在上下文中按照bean注册的工厂
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册拦截bean创建的bean处理器。
				registerBeanPostProcessors(beanFactory);

				// 初始化消息源
				initMessageSource();

				// 初始化事件多播
				initApplicationEventMulticaster();

				// 在子类上下文中初始化特殊的bean
				onRefresh();

				// 检查、注册监听bean
				registerListeners();

				// 实例化其他非懒加载的singletons.
				finishBeanFactoryInitialization(beanFactory);

				// 发布对应的事件
				finishRefresh();
			}

			catch (BeansException ex) {
    
    
				if (logger.isWarnEnabled()) {
    
    
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 删除已经创建的singletons
				destroyBeans();

				// 重置'active'标记.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
    
    
				// 重置普通缓存
				resetCommonCaches();
			}
		}
	}

prepareRefresh()

Prepare for refresh: set the startup time, set the active tag, verify whether the attribute of the required tag can be parsed, and initialize.

protected void prepareRefresh() {
    
    
		// 设置开始时间,改状态
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		if (logger.isDebugEnabled()) {
    
    
			if (logger.isTraceEnabled()) {
    
    
				logger.trace("Refreshing " + this);
			}
			else {
    
    
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// 子类实现,空方法
		initPropertySources();

		// 检查所有必须的属性是否可解析
		getEnvironment().validateRequiredProperties();

		// 存储预刷新的应用监视器
		if (this.earlyApplicationListeners == null) {
    
    
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
    
    
			// 恢复本地应用监视器到预刷新状态
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// 用于收集之前的应用事件,一旦多播准备好就发布
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

obtainFreshBeanFactory()

Performs an actual refresh of the context's underlying bean factory, closing the previous bean factory (if any), and initializing a new bean factory for the next phase of the context's lifecycle.

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    
    
		refreshBeanFactory(); //加载配置
		return getBeanFactory(); //返回类的bean工厂
	}

refreshBeanFactory()

	protected final void refreshBeanFactory() throws BeansException {
    
    
		if (hasBeanFactory()) {
    
    
			destroyBeans();    // 模板方法,删除上下文管理的所有bean,默认实现销毁此上下文中所有缓存的单例对象
			closeBeanFactory();//把SerializationId置空
		}
		try {
    
    
			DefaultListableBeanFactory beanFactory = createBeanFactory(); //创建DefaultListableBeanFactory,父工厂为null
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory); //设置BeanFactory是否允许:bean定义覆盖、循环依赖,默认均为null
			loadBeanDefinitions(beanFactory);  //为给定的BeanFactory创建一个新的XmlBeanDefinitionReader,初始化,读取beanDefinitions。
			synchronized (this.beanFactoryMonitor) {
    
    
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
    
    
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
loadBeanDefinitions(beanFactory);
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    
    
		XmlBeanDefinitionReader初始化
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		initBeanDefinitionReader(beanDefinitionReader); //留给子类提供定制的beanDefinitionReader初始化方式
		loadBeanDefinitions(beanDefinitionReader); //加载BeanDefinition
	}

As you can see, the loadBeanDefinitions method loads data from two places.

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    
    
		Resource[] configResources = getConfigResources();  //获取指向xml文件的Resource数组
		if (configResources != null) {
    
    
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();  //获取指向xml文件中指出的资源数组,也包含了location patterns,比如["spring-config.xml"]
		if (configLocations != null) {
    
    
			reader.loadBeanDefinitions(configLocations);  //通过字符串解析出Resource,然后再加载beanDefinition
		}
	}

The two methods are very close, but reader.loadBeanDefinitions(configLocations); there are more steps to obtain Resource[] from String[] in the steps, and they will eventually go to loadBeanDefinitions(Resource... resources).

	@Override
	public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
    
    
		Assert.notNull(resources, "Resource array must not be null");
		int count = 0;
		for (Resource resource : resources) {
    
    
			count += loadBeanDefinitions(resource);  //从Resource中加载BeanDefinition
		}
		return count;
	}

follow up

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    
    
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
    
    
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); //获取当下正在被加载的Resource
		if (currentResources == null) {
    
    
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
    
     //检查是否有循环加载的问题
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
    
    
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
    
    
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
    
    
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());  //继续往下看
			}
			finally {
    
    
				inputStream.close();
			}
		}
		catch (IOException ex) {
    
    
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
    
    
			currentResources.remove(encodedResource); //加载完资源,再把它从正在加载资源set中去掉
			if (currentResources.isEmpty()) {
    
    
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

Then execute the following piece of code, first read the file resource into the Document class

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
    
    

		try {
    
    
			Document doc = doLoadDocument(inputSource, resource);  //把xml文件解析为Document类,暂不深入
			int count = registerBeanDefinitions(doc, resource); //从Document类中解析出bean,并统计bean的个数。
			if (logger.isDebugEnabled()) {
    
    
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (各种各样的Exception ex) {
    
    
			throw ex;
		}
	}
registerBeanDefinitions(doc, resource)

follow up

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    
    
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    
    
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());  
	}

In the doRegisterBeanDefinitions method, any nested <beans>elements will cause recursion. Tracks the current parent delegate (nullable) in order to properly propagate and save default properties for beans. Creates new child delegate with reference to parent delegate for fallback, then finally resets this.delegate back to its original (parent) reference. This behavior simulates a stack of delegates without actually requiring a delegate

	protected void doRegisterBeanDefinitions(Element root) {
    
    
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		//获取 <beans ... profile="***" /> 中的 profile参数与当前环境是否匹配,如果不匹配则不再进行解析
		if (this.delegate.isDefaultNamespace(root)) {
    
    
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
    
    
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    
    
					if (logger.isDebugEnabled()) {
    
    
						logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}
		
		//默认实现为空,留给子类扩展
		preProcessXml(root);
		//解析BeanDefinitions
		parseBeanDefinitions(root, this.delegate);
		//默认实现为空,留给子类扩展
		postProcessXml(root);

		this.delegate = parent;
	}

parsing part

	// 在root级别("import", "alias", "bean")解析:
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    
    
		if (delegate.isDefaultNamespace(root)) {
    
    
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
    
    
				Node node = nl.item(i);
				if (node instanceof Element) {
    
    
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
    
     //检查namespace
						parseDefaultElement(ele, delegate); //解析<import> <alias> <bean> <beans>
					}
					else {
    
    
						delegate.parseCustomElement(ele);  //解析其他标签
					}
				}
			}
		}
		else {
    
    
			delegate.parseCustomElement(root);
		}
	}

parseDefaultElement(ele, delegate)

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    
    
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
    
      //<import>
			importBeanDefinitionResource(ele);               
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
    
     //<alias>
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
    
      //<bean>
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    
      //<beans>
			doRegisterBeanDefinitions(ele);
		}
	}

First look at <import>the correct processing: resolve the placeholders in the path, and load BeanDefinitions from the given resource path.

	protected void importBeanDefinitionResource(Element ele) {
    
    
		String location = ele.getAttribute(RESOURCE_ATTRIBUTE);  //获取资源路径
		if (!StringUtils.hasText(location)) {
    
      //检查是否为空
			getReaderContext().error("Resource location must not be empty", ele);
			return;
		}

		location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); //解析下路径中的占位符

		Set<Resource> actualResources = new LinkedHashSet<>(4);

		boolean absoluteLocation = false;  
		try {
    
    
			absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();  
		}
		catch (URISyntaxException ex) {
    
    
		}

		if (absoluteLocation) {
    
      //如果是绝对路径,直接通过loadBeanDefinitions方法载入BeanDefinition
			try {
    
    
				int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
				if (logger.isTraceEnabled()) {
    
    
					logger.trace("Imported " + importCount + " bean definitions from URL location [" + location + "]");
				}
			}
			catch (BeanDefinitionStoreException ex) {
    
    
				getReaderContext().error(
						"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
			}
		}
		else {
    
      // 如果是相对路径,要先创建Resource ,然后读取BeanDefinition
			try {
    
    
				int importCount;
				Resource relativeResource = getReaderContext().getResource().createRelative(location);
				if (relativeResource.exists()) {
    
    
					importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
					actualResources.add(relativeResource);
				}
				else {
    
    
					String baseLocation = getReaderContext().getResource().getURL().toString();
					importCount = getReaderContext().getReader().loadBeanDefinitions(
							StringUtils.applyRelativePath(baseLocation, location), actualResources);
				}
				if (logger.isTraceEnabled()) {
    
    
					logger.trace("Imported " + importCount + " bean definitions from relative location [" + location + "]");
				}
			}
			catch (IOException ex) {
    
    
				getReaderContext().error("Failed to resolve current resource location", ele, ex);
			}
			catch (BeanDefinitionStoreException ex) {
    
    
				getReaderContext().error(
						"Failed to import bean definitions from relative location [" + location + "]", ele, ex);
			}
		}
		Resource[] actResArray = actualResources.toArray(new Resource[0]);
		getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); //触发导入处理事件
	}

right <alias>treatment

	protected void processAliasRegistration(Element ele) {
    
    
		String name = ele.getAttribute(NAME_ATTRIBUTE);
		String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
		boolean valid = true;
		if (!StringUtils.hasText(name)) {
    
    
			getReaderContext().error("Name must not be empty", ele);
			valid = false;
		}
		if (!StringUtils.hasText(alias)) {
    
    
			getReaderContext().error("Alias must not be empty", ele);
			valid = false;
		}
		if (valid) {
    
    
			try {
    
    
				getReaderContext().getRegistry().registerAlias(name, alias);  //注册别名
			}
			catch (Exception ex) {
    
    
				getReaderContext().error("Failed to register alias '" + alias +
						"' for bean with name '" + name + "'", ele, ex);
			}
			getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); //触发别名注册事件。
		}
	}

	@Override
	public void registerAlias(String name, String alias) {
    
      
		Assert.hasText(name, "'name' must not be empty");
		Assert.hasText(alias, "'alias' must not be empty");
		synchronized (this.aliasMap) {
    
      
			if (alias.equals(name)) {
    
      //如果别名和名称一样,就忽略
				this.aliasMap.remove(alias);  
				if (logger.isDebugEnabled()) {
    
    
					logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
				}
			}
			else {
    
    
				String registeredName = this.aliasMap.get(alias);
				if (registeredName != null) {
    
    
					if (registeredName.equals(name)) {
    
      //已经存在且一样,不需要注册
						return;
					}
					if (!allowAliasOverriding()) {
    
      //存在且不一样,而且不允许别名覆盖,直接抛异常
						throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
								name + "': It is already registered for name '" + registeredName + "'.");
					}
					if (logger.isDebugEnabled()) {
    
      
						logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
								registeredName + "' with new target name '" + name + "'");
					}
				}
				checkForAliasCircle(name, alias);  //检查给定的名称是否以别名的形式指向另一个方向的给定别名,在前面捕获循环引用并抛出相应的IllegalStateException
				this.aliasMap.put(alias, name); //把别名放进ConcurrentHashMap<String,String>中
				if (logger.isTraceEnabled()) {
    
    
					logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
				}
			}
		}
	}

The focus depends on the right <bean>treatment

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    
    
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  //BeanDefinitionHolder中包含了beanDefinition、beanName、aliases三个属性。
		if (bdHolder != null) {
    
    
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  //解析自定义属性
			try {
    
    
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); //注册BeanDefinition,、继续跟进
			}
			catch (BeanDefinitionStoreException ex) {
    
    
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  //触发bean注册事件
		}
	}
	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {
    
    

		String beanName = definitionHolder.getBeanName(); //注册名字
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
    
    
			for (String alias : aliases) {
    
    
				registry.registerAlias(beanName, alias);//注册别名
			}
		}
	}
	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
    
    

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
    
    
			try {
    
    
				((AbstractBeanDefinition) beanDefinition).validate();  //验证BeanDefinition
			}
			catch (BeanDefinitionValidationException ex) {
    
    
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		//检查是否注册过,如果注册过是否可以重写
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
    
    
			if (!isAllowBeanDefinitionOverriding()) {
    
    
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
    
    
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
    
    
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
    
    
				if (logger.isDebugEnabled()) {
    
    
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
    
    
				if (logger.isTraceEnabled()) {
    
    
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition); //放进ConcurrentHashMap<String,BeanDefinition>
		}
		else {
    
    
			if (hasBeanCreationStarted()) {
    
     //如果已经开始创建Bean,就要防止并发问题
				synchronized (this.beanDefinitionMap) {
    
     // 把bean
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;  //beanDefinitionNames (ArrayList)中新增name
					removeManualSingletonName(beanName);  //从手动注册单例名单中移除。
				}
			}
			else {
    
     
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
    
    
			resetBeanDefinition(beanName);
		}
	}

The right <beans>processing
Register all BeanDefinitions in the root element, and return to doRegisterBeanDefinitions(doc.getDocumentElement()); above.

	protected void doRegisterBeanDefinitions(Element root) {
    
    
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		if (this.delegate.isDefaultNamespace(root)) {
    
    
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
    
    
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				// We cannot use Profiles.of(...) since profile expressions are not supported
				// in XML config. See SPR-12458 for details.
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    
    
					if (logger.isDebugEnabled()) {
    
    
						logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}

		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

getBeanFactory()

At this point, the Bean container has been initialized, and the configuration of the Bean is converted into a BeanDefinition accordingly, and then all BeanDefinitions are registered in the beanDefinitionMap. getBeanFactory() gets the beanFactory just initialized.

	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
    
    
		synchronized (this.beanFactoryMonitor) {
    
    
			if (this.beanFactory == null) {
    
    
				throw new IllegalStateException("BeanFactory not initialized or already closed - " +
						"call 'refresh' before accessing beans via the ApplicationContext");
			}
			return this.beanFactory;
		}
	}

Due to the length of the article, it is still being sorted out.

Guess you like

Origin blog.csdn.net/weixin_44532671/article/details/123030349