SpringIoc容器架构分析
- BeanFactory
- HierarchicalBeanFactory
- ListableBeanFactory
- AutowireCapableBeanFactory
- AbstractBeanFactory
- AbstractAutowireCapableBeanFactory
- DefaultListableBeanFactory
- ApplicationContext
- ConfigurableApplicationContext
- ApplicationContext除BeanFactory外的其他父接口
- AbstractApplicationContext
- GenericApplicationContext
- AnnotationConfigApplicationContext
分析Spring的容器体系,以目前使用较为广泛的AnnotationConfigApplicationContext为例来分析,类继承体系图如下:
BeanFactory
顶层的BeanFactory接口仅提供最基本的获取bean的方法,以及获取bean的provide(bean所在容器对象)的方法。
getBean系列方法:获取bean对象
getBeanProvider:获取bean所在的容器
containsBean:bean是否存在
isSingleton:bean是否是单例
isPrototype:bean是否是原型bean
isTypeMatch:给定的bean是否匹配指定的类型
getType:获取bean的类型
getAliases:获取bean的别名列表
HierarchicalBeanFactory
层次化BeanFactory,从它的名字可知,他提供的核心是层次,层次就是分层,容器分层的话就是有父子容器,这个接口很简单,就是提供两个接口:
java
public interface HierarchicalBeanFactory extends BeanFactory {
/**
* Return the parent bean factory, or {@code null} if there is none.
*/
@Nullable
BeanFactory getParentBeanFactory();
/**
* Return whether the local bean factory contains a bean of the given name,
* ignoring beans defined in ancestor contexts.
* <p>This is an alternative to {@code containsBean}, ignoring a bean
* of the given name from an ancestor bean factory.
* @param name the name of the bean to query
* @return whether a bean with the given name is defined in the local factory
* @see BeanFactory#containsBean
*/
boolean containsLocalBean(String name);
}
ListableBeanFactory
可列举的bean,从名字可以知道它的主要特点是:可列举。可列举是什么意思,就是它提供接口可以一次性获取到这个容器内部的所有bean信息,而不是像BeanFactory一样需要通过getBean一个一个获取bean。这里需要注意,如果当前容器同时是ListableBeanFactory和HierarchicalBeanFactory,那么在查找bean的过程中不会去父容器中查找。
containsBeanDefinition:是否包含指定bean名称的bean元信息
String[] getBeanDefinitionNames(); 获取所有bean的名字。
getBeanProvider系列方法:获取bean的容器
String[] getBeanNamesForType(ResolvableType type);返回满足给定bean类型的所有bean名字。
Map<String, T> getBeansOfType(@Nullable Class type) throws BeansException; 返回指定类型的bean
String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);获取包含指定注解的所有bean名字。
findAnnotationOnBean:给定bean名字,查它的注解
A findAnnotationOnBean(
String beanName, Class annotationType, boolean allowFactoryBeanInit)
throws NoSuchBeanDefinitionException;
总结:提供列举bean的接口,提供获取bean注解的接口。
AutowireCapableBeanFactory
继承自BeanFactory,提供组件的自动注入功能。可以为一些现有的没有被spring管理的bean提供自动注入功能,比如自定义的组件依赖spring管理的bean,可借助此接口提供的方法完成注入。比如,如果需要给自定义的Servlet等没有被SpringFramework统一管理的bean注入组件,可以在获取AutowriteCapableBeanFactory之后调用其API实现依赖注入。
这个接口定义了创建bean的方法、运行beanPostProcess的方法,resolveBean等方法,主要功能就是完成bean的创建及依赖注入。
java
<T> T createBean(Class<T> beanClass) throws BeansException;
void autowireBean(Object existingBean) throws BeansException;
Object configureBean(Object existingBean, String beanName) throws BeansException;
void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
Object initializeBean(Object existingBean, String beanName) throws BeansException;
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException;
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException;
void destroyBean(Object existingBean);
<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
#ConfigurableBeanFactory
继承关系如下:
java
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry
这个接口的功能如其名(Configurable),主要提供带配置的功能,可以调用它定义的方法对BeanFactory进行修改扩展等操作。但是官方不建议开发者去调用这个接口的方法,因为原则上程序在运行期间对BeanFactory进行频繁地改动不好,此时应该只有读的操作。其提供的主要方法(主要例句set等修改类方法)如下:
java
void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);
void setTempClassLoader(@Nullable ClassLoader tempClassLoader);
void setCacheBeanMetadata(boolean cacheBeanMetadata);
void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);
void setConversionService(@Nullable ConversionService conversionService);
void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
void setTypeConverter(TypeConverter typeConverter);
void addEmbeddedValueResolver(StringValueResolver valueResolver);
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
void registerScope(String scopeName, Scope scope);
void registerDependentBean(String beanName, String dependentBeanName);
void destroyBean(String beanName, Object beanInstance);
AbstractBeanFactory
它是BeanFactory最基础的抽象实现,仅有部分功能。
1、 能够从配置源(XML、LDAP、RDBMS)获取Bean的定义信息BeanDefinition。
2、 提供单实例Bean的缓存,单实例/原型Bean的裁定FactoryBean处理,Bean对象别名存储、用于子Bean定义BeanDefinition合并以及Bean销毁。
3、模板方法getBeanDefinition和createBean规范了Bean定义读取和创建bean的过程,子类实现具体的业务逻辑。
实现了getBean方法,里面会实际创建bean,在doGetBean方法中实现了bean创建基本流程规范。
提供了判断bean的scope的实现(是否单例或者原型)。
实现isTypeMacth方法
实现getType方法
实现getAliases方法
实现get、setParenBeanFactory方法
实现addBeanPostProcessor方法
AbstractAutowireCapableBeanFactory
继承关系如下:
java
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory
实现了默认bean对象创建逻辑的BeanFactory接口的抽象类,除了实现父类AbstractBeanFactory的createBean方法,还实现了AutowireCapableBeanFactory接口的方法,即Bean对象真正的创建动作都在此实现。
实现bean对象的创建、属性的赋值和依赖注入以及Bean的初始化逻辑执行。
子类需要实现resolveDependency方法,解析Bean的成员中定义的属性依赖关系,由子类DefaultListableBeanFactory实现。
这个类主要实现的是Bean创建,而BeanDefinition的读取解析工作没在这里实现。
DefaultListableBeanFactory
类继承关系如下:
java
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
是一个成熟的落地实现,其还实现了BeanDefinitionRegistry接口,完成对BeanDefinition的读取功能,即完成Bean定义信息加载。
一般地,首先需要先注册Bean的定义信息,再完成Bean的创建和初始化动作,这个类就实现了这个逻辑。
需要注意的是,此类不实现特定Bean信息的读取和解析,而是通过委托的方式,让其他BeanDefinitionReader实现。
BeanDefinitionRegistry定义如下:
java
/**
* Interface for registries that hold bean definitions, for example RootBeanDefinition
* and ChildBeanDefinition instances. Typically implemented by BeanFactories that
* internally work with the AbstractBeanDefinition hierarchy.
*
* <p>This is the only interface in Spring's bean factory packages that encapsulates
* <i>registration</i> of bean definitions. The standard BeanFactory interfaces
* only cover access to a <i>fully configured factory instance</i>.
*
* <p>Spring's bean definition readers expect to work on an implementation of this
* interface. Known implementors within the Spring core are DefaultListableBeanFactory
* and GenericApplicationContext.
*
* @author Juergen Hoeller
* @since 26.11.2003
* @see org.springframework.beans.factory.config.BeanDefinition
* @see AbstractBeanDefinition
* @see RootBeanDefinition
* @see ChildBeanDefinition
* @see DefaultListableBeanFactory
* @see org.springframework.context.support.GenericApplicationContext
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see PropertiesBeanDefinitionReader
*/
public interface BeanDefinitionRegistry extends AliasRegistry {
/**
* Register a new bean definition with this registry.
* Must support RootBeanDefinition and ChildBeanDefinition.
* @param beanName the name of the bean instance to register
* @param beanDefinition definition of the bean instance to register
* @throws BeanDefinitionStoreException if the BeanDefinition is invalid
* @throws BeanDefinitionOverrideException if there is already a BeanDefinition
* for the specified bean name and we are not allowed to override it
* @see GenericBeanDefinition
* @see RootBeanDefinition
* @see ChildBeanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
/**
* Remove the BeanDefinition for the given name.
* @param beanName the name of the bean instance to register
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* Return the BeanDefinition for the given bean name.
* @param beanName name of the bean to find a definition for
* @return the BeanDefinition for the given name (never {@code null})
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* Check if this registry contains a bean definition with the given name.
* @param beanName the name of the bean to look for
* @return if this registry contains a bean definition with the given name
*/
boolean containsBeanDefinition(String beanName);
/**
* Return the names of all beans defined in this registry.
* @return the names of all beans defined in this registry,
* or an empty array if none defined
*/
String[] getBeanDefinitionNames();
/**
* Return the number of beans defined in the registry.
* @return the number of beans defined in the registry
*/
int getBeanDefinitionCount();
/**
* Determine whether the given bean name is already in use within this registry,
* i.e. whether there is a local bean or alias registered under this name.
* @param beanName the name to check
* @return whether the given bean name is already in use
*/
boolean isBeanNameInUse(String beanName);
}
主要定义了BeanDefinition的注册,删除和获取等方法
ApplicationContext
应用程序上下文根接口继承BeanFactory接口,且继承另外几个接口,这几个接口提供的能力就是ApplicationContext除了BeanFactory本身能力以外的核心能力。
源码:
java
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver
从父接口的名字,大概知道其核心能力包括:环境配置,访问Bean,加载资源文件,事件发布监听等核心能力。
环境配置:加在application.yaml等配置文件,命令行参数,环境变量,操作系统环境等
事件监听:Springbean的生命周期事件
这个接口本身代码不多,就几个看起来不太重要的接口:
java
@Nullable
String getId();
/**
* Return a name for the deployed application that this context belongs to.
* @return a name for the deployed application, or the empty String by default
*/
String getApplicationName();
/**
* Return a friendly name for this context.
* @return a display name for this context (never {@code null})
*/
String getDisplayName();
/**
* Return the timestamp when this context was first loaded.
* @return the timestamp (ms) when this context was first loaded
*/
long getStartupDate();
/**
* Return the parent context, or {@code null} if there is no parent
* and this is the root of the context hierarchy.
* @return the parent context, or {@code null} if there is no parent
*/
@Nullable
ApplicationContext getParent();
/**
* Expose AutowireCapableBeanFactory functionality for this context.
* <p>This is not typically used by application code, except for the purpose of
* initializing bean instances that live outside the application context,
* applying the Spring bean lifecycle (fully or partly) to them.
* <p>Alternatively, the internal BeanFactory exposed by the
* {@link ConfigurableApplicationContext} interface offers access to the
* {@link AutowireCapableBeanFactory} interface too. The present method mainly
* serves as a convenient, specific facility on the ApplicationContext interface.
* <p><b>NOTE: As of 4.2, this method will consistently throw IllegalStateException
* after the application context has been closed.</b> In current Spring Framework
* versions, only refreshable application contexts behave that way; as of 4.2,
* all application context implementations will be required to comply.
* @return the AutowireCapableBeanFactory for this context
* @throws IllegalStateException if the context does not support the
* {@link AutowireCapableBeanFactory} interface, or does not hold an
* autowire-capable bean factory yet (e.g. if {@code refresh()} has
* never been called), or if the context has been closed already
* @see ConfigurableApplicationContext#refresh()
* @see ConfigurableApplicationContext#getBeanFactory()
*/
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
ConfigurableApplicationContext
可配置应用程序上下文,关键在:可配置的。就是可以修改Application,从其提供的接口方法中,我们可以看可以修改什么:
java
/**
* Set the unique id of this application context.
* @since 3.0
*/
void setId(String id);
/**
* Set the parent of this application context.
* <p>Note that the parent shouldn't be changed: It should only be set outside
* a constructor if it isn't available when an object of this class is created,
* for example in case of WebApplicationContext setup.
* @param parent the parent context
* @see org.springframework.web.context.ConfigurableWebApplicationContext
*/
void setParent(@Nullable ApplicationContext parent);
/**
* Set the {@code Environment} for this application context.
* @param environment the new environment
* @since 3.1
*/
void setEnvironment(ConfigurableEnvironment environment);
/**
* Return the {@code Environment} for this application context in configurable
* form, allowing for further customization.
* @since 3.1
*/
@Override
ConfigurableEnvironment getEnvironment();
/**
* Set the {@link ApplicationStartup} for this application context.
* <p>This allows the application context to record metrics
* during startup.
* @param applicationStartup the new context event factory
* @since 5.3
*/
void setApplicationStartup(ApplicationStartup applicationStartup);
/**
* Return the {@link ApplicationStartup} for this application context.
* @since 5.3
*/
ApplicationStartup getApplicationStartup();
/**
* Add a new BeanFactoryPostProcessor that will get applied to the internal
* bean factory of this application context on refresh, before any of the
* bean definitions get evaluated. To be invoked during context configuration.
* @param postProcessor the factory processor to register
*/
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
/**
* Add a new ApplicationListener that will be notified on context events
* such as context refresh and context shutdown.
* <p>Note that any ApplicationListener registered here will be applied
* on refresh if the context is not active yet, or on the fly with the
* current event multicaster in case of a context that is already active.
* @param listener the ApplicationListener to register
* @see org.springframework.context.event.ContextRefreshedEvent
* @see org.springframework.context.event.ContextClosedEvent
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* Specify the ClassLoader to load class path resources and bean classes with.
* <p>This context class loader will be passed to the internal bean factory.
* @since 5.2.7
* @see org.springframework.core.io.DefaultResourceLoader#DefaultResourceLoader(ClassLoader)
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#setBeanClassLoader
*/
void setClassLoader(ClassLoader classLoader);
/**
* Register the given protocol resolver with this application context,
* allowing for additional resource protocols to be handled.
* <p>Any such resolver will be invoked ahead of this context's standard
* resolution rules. It may therefore also override any default rules.
* @since 4.3
*/
void addProtocolResolver(ProtocolResolver resolver);
/**
* Load or refresh the persistent representation of the configuration, which
* might be from Java-based configuration, an XML file, a properties file, a
* relational database schema, or some other format.
* <p>As this is a startup method, it should destroy already created singletons
* if it fails, to avoid dangling resources. In other words, after invocation
* of this method, either all or no singletons at all should be instantiated.
* @throws BeansException if the bean factory could not be initialized
* @throws IllegalStateException if already initialized and multiple refresh
* attempts are not supported
*/
void refresh() throws BeansException, IllegalStateException;
/**
* Register a shutdown hook with the JVM runtime, closing this context
* on JVM shutdown unless it has already been closed at that time.
* <p>This method can be called multiple times. Only one shutdown hook
* (at max) will be registered for each context instance.
* <p>As of Spring Framework 5.2, the {@linkplain Thread#getName() name} of
* the shutdown hook thread should be {@link #SHUTDOWN_HOOK_THREAD_NAME}.
* @see java.lang.Runtime#addShutdownHook
* @see #close()
*/
void registerShutdownHook();
由代码可知,主要包括设置父上下文、设置环境、增加BeanFactoryPostProcessor、增加应用程序监听器等。
ApplicationContext除BeanFactory外的其他父接口
ResourcePatternResolver
这个接口的官方注释翻译如下:
java
/**
用于将位置模式(例如,Ant样式的路径模式)解析为{@link Resource}对象的策略接口。
这是{@link org.springframework.core.io.ResourceLoader}接口的扩展。传入的{@code ResourceLoader}(例如,在上下文中运行时通过
{@link org.springframework.context.ResourceLoaderAware}传入的{@link org.springframework.context.ApplicationContext})可以检查它是否也实现了这个扩展接口。
{@link PathMatchingResourcePatternResolver}是一个独立的实现,可以在{@code ApplicationContext}之外使用,也被
{@link ResourceArrayPropertyEditor}用于填充{@code Resource}数组bean属性。
可以与任何类型的位置模式一起使用------例如,{@code "/WEB-INF/*-context.xml"}。但是,输入模式必须与策略实现匹配。此接口仅指定转换方法,而不是特定的模式格式。
此接口还为所有来自类路径的匹配资源定义了{@code "classpath*:"}资源前缀。请注意,资源位置也可能包含占位符------例如{@code "/beans-*.xml"}。JAR文件或类路径中的不同目录可以包含相同名称的多个文件。
@author Juergen Hoeller
@since 1.0.2
@see org.springframework.core.io.Resource
@see org.springframework.core.io.ResourceLoader
@see org.springframework.context.ApplicationContext
@see org.springframework.context.ResourceLoaderAware */
主要是用于将路径解析为Resource对象,供后续读取
EnvironmentCapable
该接口提供获取Environment对象的接口,用于获取spring英勇的环境信息。接口仅有一个方法:
java
public interface EnvironmentCapable {
/**
* Return the {@link Environment} associated with this component.
*/
Environment getEnvironment();
}
MessageSource
国际化支持组件,主要定义了getMessage方法,用于获取不同语言的信息。下面给一个方法的源码看看:
java
/**
* Try to resolve the message. Return default message if no message was found.
* @param code the message code to look up, e.g. 'calculator.noRateSet'.
* MessageSource users are encouraged to base message names on qualified class
* or package names, avoiding potential conflicts and ensuring maximum clarity.
* @param args an array of arguments that will be filled in for params within
* the message (params look like "{0}", "{1,date}", "{2,time}" within a message),
* or {@code null} if none
* @param defaultMessage a default message to return if the lookup fails
* @param locale the locale in which to do the lookup
* @return the resolved message if the lookup was successful, otherwise
* the default message passed as a parameter (which may be {@code null})
* @see #getMessage(MessageSourceResolvable, Locale)
* @see java.text.MessageFormat
*/
@Nullable
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
ApplicationEventPublisher
事件发布器,在spring的应用生命周期中,会发布各种事件,注册的监听器收到事件之后可以执行相应的逻辑。这是发布-订阅模式的应用。主要有以下4个对象:
事件源:发布事件的对象
事件:事件源发布的信息/做出的动作
广播器:事件真正广播给监听器的对象,执行事件广播动作,这里EventPublisher就是
监听器:监听事件的对象
这个接口注意定义了publishEvent方法,用于发布事件。
AbstractApplicationContext
此抽象类开始实现了父接口定义的大部分特性和功能。采用模板方法模式,具体的实现还是要子类来完成。它仅简单实现应用上下文的基本功能,不强制约束配置的承载形式(XML、注解驱动等)。
与普通BeanFactory相比,ApplicationContext能够检查在其内部bean对象工厂中定义的特殊Bean,这类自动注册在上下文中定义为Bean的包括BeanfactoryPostProcessors、BeanPostProcessors和ApplicationListeners。
ApplicationContext实现国际化接口和事件广播器的方式可以是通过提供内部bean的方式,比如一个messageSource的Bean完成国际化的能力。一个applicationEventMulticaster的bean完成事件广播器功能。
加载资源文件一般是继承DefaultResourceLoader的策略,从类路径下加载;但是可以被子类覆盖,比如在web场景中,可以从ServletContext中加载(扩展的子类ServletContextResourceLoader)。
GenericApplicationContext
继承关系如下:
java
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry
此类是注解驱动IOC容器的第一个非抽象实现,已经具备ApplicationContext所有的基本能力了。
内部持有一个DefaultListableBeanFactory,实现了BeanDefinitionRegistry接口,允许任何Bean定义读取其应用于此容器中。ApplicationContext通过组合BeanFactory的方式获得容器功能
实现了BeanDefinitionRegistry接口,可以自定义注册一些Bean,其实现是由DefaultListableBeanFactory的方法完成,采用的是委托机制:
java
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
其内部持有的DefaultListableBeanFactory在构造函数中初始化了,只允许刷新一次。
AnnotationConfigApplicationContext
继承关系如下
java
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry
独立的注解驱动的ApplicationContext,继承GenericApplicationContext,BeanFactory仅能刷新一次。接受组件类作为输入(特别是@Configuration注解的类),一个@Configuration注解的类相当于一个XML配置文件,注解配置类就是驱动加载源。
它允许使用register(Class...)方法直接传入指定的配置类,也可以采用scan进行类路径的包扫描。如果有多个@Configuration注解类,后面的类中定义的Bean配置会覆盖前面的相同定义。
这个类代码不是很多,直接看源码;
java
/**
* Standalone application context, accepting <em>component classes</em> as input —
* in particular {@link Configuration @Configuration}-annotated classes, but also plain
* {@link org.springframework.stereotype.Component @Component} types and JSR-330 compliant
* classes using {@code javax.inject} annotations.
*
* <p>Allows for registering classes one by one using {@link #register(Class...)}
* as well as for classpath scanning using {@link #scan(String...)}.
*
* <p>In case of multiple {@code @Configuration} classes, {@link Bean @Bean} methods
* defined in later classes will override those defined in earlier classes. This can
* be leveraged to deliberately override certain bean definitions via an extra
* {@code @Configuration} class.
*
* <p>See {@link Configuration @Configuration}'s javadoc for usage examples.
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 3.0
* @see #register
* @see #scan
* @see AnnotatedBeanDefinitionReader
* @see ClassPathBeanDefinitionScanner
* @see org.springframework.context.support.GenericXmlApplicationContext
*/
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
/**
* Create a new AnnotationConfigApplicationContext with the given DefaultListableBeanFactory.
* @param beanFactory the DefaultListableBeanFactory instance to use for this context
*/
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given component classes and automatically refreshing the context.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
/**
* Create a new AnnotationConfigApplicationContext, scanning for components
* in the given packages, registering bean definitions for those components,
* and automatically refreshing the context.
* @param basePackages the packages to scan for component classes
*/
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
/**
* Propagate the given custom {@code Environment} to the underlying
* {@link AnnotatedBeanDefinitionReader} and {@link ClassPathBeanDefinitionScanner}.
*/
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
/**
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
* <p>Default is {@link AnnotationBeanNameGenerator}.
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
* and/or {@link #scan(String...)}.
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
* @see AnnotationBeanNameGenerator
* @see FullyQualifiedAnnotationBeanNameGenerator
*/
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.reader.setBeanNameGenerator(beanNameGenerator);
this.scanner.setBeanNameGenerator(beanNameGenerator);
getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
/**
* Set the {@link ScopeMetadataResolver} to use for registered component classes.
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
* and/or {@link #scan(String...)}.
*/
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
this.reader.setScopeMetadataResolver(scopeMetadataResolver);
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
//---------------------------------------------------------------------
// Implementation of AnnotationConfigRegistry
//---------------------------------------------------------------------
/**
* Register one or more component classes to be processed.
* <p>Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
* @see #scan(String...)
* @see #refresh()
*/
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
.tag("classes", () -> Arrays.toString(componentClasses));
this.reader.register(componentClasses);
registerComponentClass.end();
}
/**
* Perform a scan within the specified base packages.
* <p>Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param basePackages the packages to scan for component classes
* @see #register(Class...)
* @see #refresh()
*/
@Override
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan")
.tag("packages", () -> Arrays.toString(basePackages));
this.scanner.scan(basePackages);
scanPackages.end();
}
//---------------------------------------------------------------------
// Adapt superclass registerBean calls to AnnotatedBeanDefinitionReader
//---------------------------------------------------------------------
@Override
public <T> void registerBean(@Nullable String beanName, Class<T> beanClass,
@Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) {
this.reader.registerBean(beanClass, beanName, supplier, customizers);
}
}
可见,其主要方法是register和scan,分别委托给其他类AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner实现。