/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

/**
 * The root interface for accessing a Spring bean container.
 * This is the basic client view of a bean container;
 * further interfaces such as {@link ListableBeanFactory} and
 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
 * are available for specific purposes.
 *
 * <p>This interface is implemented by objects that hold a number of bean definitions,
 * each uniquely identified by a String name. Depending on the bean definition,
 * the factory will return either an independent instance of a contained object
 * (the Prototype design pattern), or a single shared instance (a superior
 * alternative to the Singleton design pattern, in which the instance is a
 * singleton in the scope of the factory). Which type of instance will be returned
 * depends on the bean factory configuration: the API is the same. Since Spring
 * 2.0, further scopes are available depending on the concrete application
 * context (e.g. "request" and "session" scopes in a web environment).
 *
 * <p>The point of this approach is that the BeanFactory is a central registry
 * of application components, and centralizes configuration of application
 * components (no more do individual objects need to read properties files,
 * for example). See chapters 4 and 11 of "Expert One-on-One J2EE Design and
 * Development" for a discussion of the benefits of this approach.
 *
 * <p>Note that it is generally better to rely on Dependency Injection
 * ("push" configuration) to configure application objects through setters
 * or constructors, rather than use any form of "pull" configuration like a
 * BeanFactory lookup. Spring's Dependency Injection functionality is
 * implemented using this BeanFactory interface and its subinterfaces.
 *
 * <p>Normally a BeanFactory will load bean definitions stored in a configuration
 * source (such as an XML document), and use the {@code org.springframework.beans}
 * package to configure the beans. However, an implementation could simply return
 * Java objects it creates as necessary directly in Java code. There are no
 * constraints on how the definitions could be stored: LDAP, RDBMS, XML,
 * properties file, etc. Implementations are encouraged to support references
 * amongst beans (Dependency Injection).
 *
 * <p>In contrast to the methods in {@link ListableBeanFactory}, all of the
 * operations in this interface will also check parent factories if this is a
 * {@link HierarchicalBeanFactory}. If a bean is not found in this factory instance,
 * the immediate parent factory will be asked. Beans in this factory instance
 * are supposed to override beans of the same name in any parent factory.
 *
 * <p>Bean factory implementations should support the standard bean lifecycle interfaces
   as far as possible. The full set of initialization methods and their standard order is:B
 * <ol>
 * initializeBean 初始化后调用-->AbstractAutowireCapableBeanFactory#invokeAwareMethods(java.lang.String, java.lang.Object)
 * <li>BeanNameAware's {@code invokeAwareMethods}
 * <li>BeanClassLoaderAware's {@code setBeanClassLoader}
 * <li>BeanFactoryAware's {@code setBeanFactory}
 *
 * ApplicationContextAwareProcessor#postProcessBeforeInitialization----> #invokeAwareInterfaces(java.lang.Object)
 * <li>EnvironmentAware's {@code setEnvironment}
 * <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver} 获取properties文件属性值
 * <li>ResourceLoaderAware's {@code setResourceLoader}
 * (only applicable when running in an application context)
 * <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
 * (only applicable when running in an application context)
 * <li>MessageSourceAware's {@code setMessageSource}
 * (only applicable when running in an application context)
 * <li>ApplicationContextAware's {@code setApplicationContext}
 * (only applicable when running in an application context)
 * org.springframework.web.context.support.ServletContextAwareProcessor   Spring MVC Web中注册的
 * <li>ServletContextAware's {@code setServletContext}
 * (only applicable when running in a web application context)
 * InitDestroyAnnotationBeanPostProcessor-继承关系-CommonAnnotationBeanPostProcessor
 * <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors @PostConstruct
 * <li>InitializingBean's {@code afterPropertiesSet}
 * <li>a custom init-method definition
 * <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
 * </ol>
 *
 * <p>On shutdown of a bean factory, the following lifecycle methods apply:
 * <ol>InitDestroyAnnotationBeanPostProcessor-继承关系-CommonAnnotationBeanPostProcessor
 * <li>{@code postProcessBeforeDestruction} methods of InitDestroyAnnotationBeanPostProcessor @PreDestroy
 * <li>DisposableBean's {@code destroy}
 * <li>a custom destroy-method definition
 * </ol>
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 13 April 2001
 * IOCbean工厂的顶级接口   定义一系列对bean的操作
 */
public interface BeanFactory {

	/**
	 * 工厂Bean的前缀
	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
	 * will return the factory, not the instance returned by the factory.
	 */
	String FACTORY_BEAN_PREFIX = "&";


	/**
	 * 通过bean 去容器中获取一个bean对象
	 * @param name 名称(有可能是bean的真正的名称 也有可能是工厂bean的名称 也有可能是bean的别名)
	 * @return 返回bean实例
	 * @throws NoSuchBeanDefinitionException 抛出的异常，容器中没有该bean的定义
	 * @throws BeansException if the bean could not be obtained
	 */
	Object getBean(String name) throws BeansException;

	/**
	 * 通过bean 去容器中获取一个bean对象
	 * @param name 名称(有可能是bean的真正的名称 也有可能是工厂bean的名称 也有可能是bean的别名)
	 * @param requiredType 去容器中获取Bean的class类型 可以是实现的接口和父类
	 * @return 返回Bean对应的实例
	 * @throws NoSuchBeanDefinitionException 抛出的异常，容器中没有该bean的定义
	 * @throws BeanNotOfRequiredTypeException 容器中没有指定class类型的bean
	 * @throws BeansException bean还没有被创建
	 */
	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	/**
	 *通过bean 去容器中获取一个bean对象
	 * @param name 名称(有可能是bean的真正的名称 也有可能是工厂bean的名称 也有可能是bean的别名)
	 * @param args 这个是用于指定传入获取bean的构造函数的参数,通过传入该参数，那么就可以明确的知道去调用哪个构造函数是实例化对象
	 * @return 返回Bean对应的实例
	 * @throws NoSuchBeanDefinitionException 抛出的异常，容器中没有该bean的定义
	 * @throws BeanDefinitionStoreException 主要用于多例模式下的构造器创建？？？？暂时没理解
	 * @throws BeansException bean还没有被创建
	 * @since 2.5
	 */
	Object getBean(String name, Object... args) throws BeansException;

	/**
	 *通过指定的bean的类型去容器中获取对象  若容器中有多个想同类型的bean
	 * 我们通过ctx.getBean(beanType.class) 就会抛出异常
	 * @param requiredType class对象需要的类型
	 * @return 返回的bean对象
	 * @throws NoSuchBeanDefinitionException 没有对应class的bean定义
	 * @throws NoUniqueBeanDefinitionException 找到多个匹配的
	 * @throws BeansException 创建bean的实例
	 * @since 3.0
	 * @see ListableBeanFactory
	 */
	<T> T getBean(Class<T> requiredType) throws BeansException;

	/**
	 *获取bean实例
	 * @param requiredType bean的类型
	 * @param args 构造函数的参数的类型，在实例化的过程中不需要去推断构造函数了
	 * @return bean实例
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 * @throws BeanDefinitionStoreException if arguments have been given but
	 * the affected bean isn't a prototype
	 * @throws BeansException if the bean could not be created
	 * @since 4.1
	 */
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;


	/**
	 *判断我们的容器中是否包含了当前的bean对象
	 * @param name the name of the bean to query
	 * @return whether a bean with the given name is present
	 */
	boolean containsBean(String name);

	/**
	 *判断当前的bean是不是单例的
	 * @param name the name of the bean to query
	 * @return whether this bean corresponds to a singleton instance
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #isPrototype
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/**
	 *是不是原型的
	 * @param name the name of the bean to query
	 * @return whether this bean will always deliver independent instances
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @since 2.0.3
	 * @see #getBean
	 * @see #isSingleton
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 *是不是匹配的类型
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the name of the bean to query
	 * @param typeToMatch the type to match against (as a {@code ResolvableType})
	 * @return {@code true} if the bean type matches,
	 * {@code false} if it doesn't match or cannot be determined yet
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @since 4.2
	 * @see #getBean
	 * @see #getType
	 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 *是不是匹配的类型
	 * @param name the name of the bean to query
	 * @param typeToMatch the type to match against (as a {@code Class})
	 * @return {@code true} if the bean type matches,
	 * {@code false} if it doesn't match or cannot be determined yet
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @since 2.0.1
	 * @see #getBean
	 * @see #getType
	 */
	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 *通过beanName获取对应bean的class类型
	 * @param name the name of the bean to query
	 * @return the type of the bean, or {@code null} if not determinable
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @since 1.1.2
	 * @see #getBean
	 * @see #isTypeMatch
	 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	/**
	 *获取bean的所有的别名
	 * <p>Will ask the parent factory if the bean cannot be found in this factory instance.
	 * @param name the bean name to check for aliases
	 * @return the aliases, or an empty array if none
	 * @see #getBean
	 */
	String[] getAliases(String name);

}
