Spring IoC 容器是整个框架中最核心、最关键的一部分内容,也是许多面试考察中的重要内容。 今天我将从 Spring 接口源码入手,与大家一块学习下容器相关的内容。 今天的内容包括三部分,第一部分是 Spring 中 BeanFactory 接口及其子类(接口)的梳理;第二部分是对 ApplicationContext 接口及其子类实现的梳理; 最后一部分从应用的角度介绍容器的使用、配置、定制化等内容。
官方文档中,对 BeanFactory 定义或介绍为:
The root interface for accessing a Spring bean container. This interface is implemented by objects that hold a number of bean definitions, each uniquely identified by a String name.
这个定义,简单、明确的指明了 BeanFactory 的功能,它负责管理 Bean,并通过 String 类型的名称来区分不同的 Bean。 BeanFactory 定义了 Spring 框架中 Bean 容器应当具备的最基本的能力。 这些能力可以分为如下几类:
boolean containsBean(String name);
复制代码
T getBean(Class requiredType) throws BeansException;
T getBean(Class requiredType, Object... args) throws BeansException;
Object getBean(String name) throws BeansException;
T getBean(String name, Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
ObjectProvider getBeanProvider(Class requiredType);
ObjectProvider getBeanProvider(ResolvableType requiredType);
复制代码
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
复制代码
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
复制代码
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
复制代码
BeanFactory 接口的子类(接口),都在某些特定方面增强了它的功能,例如:
BeanFactory getParentBeanFactory();
boolean containsLocalBean(String name);
复制代码
Map getBeansOfType(@Nullable Class type) throws BeansException;
Map getBeansOfType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
Map getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
int getBeanDefinitionCount();
String[] getBeanDefinitionNames();
复制代码
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException;
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException;
NamedBeanHolder resolveNamedBean(Class requiredType) throws BeansException;
Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
复制代码
protected T doGetBean(
String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
/** 对于已经初始化过的单例,直接取出 */
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/**
* 如果当前容器中不包含 containsBeanDefinition(beanName) == false
* 则尝试从父容器中取
* 根据父容器的类型,调用不同的接口
*/
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
/**
* 当前容器中没有、父容器中也没找到,则尝试创建(实例化)
*/
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
/**
* 取得 BeanName 对应的 BeanDefinition 对象
*/
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
/**
* 是否有依赖项,若有,则先创建依赖项
*/
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
/** 循环依赖的一种情况,发现后抛异常 */
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
/** 最终又到 doGetBean */
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/** 所有的依赖都创建完毕后,创建当前 Bean */
// Create bean instance.
if (mbd.isSingleton()) {
/** 这个过程在之前分析创建 Bean 的过程时分析过 */
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
/** 过程与创建单例 Bean 类似,不同在于前后的 beforeXXX 和 afterXXX */
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
/** request、session、application 等类型的作用范围在这里处理,用户自定义的作用范围也在这里处理 */
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
/** 与 prototype 类似 */
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
/** 根据 requiredType 的情况,确定是否需要做类型转换 */
return adaptBeanInstance(name, beanInstance, requiredType);
}
复制代码
AbstractBeanFactory 预留了三个抽象方法由子类实现,containsBeanDefinition、getBeanDefinition 和 createBean。
ApplicationContext 的接口定义如下:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver { ... }
复制代码
从接口定义上看,ApplicationContext 继承了 ListableBeanFactory 和 HierarchicalBeanFactory,因此具备它们所具有的能力(这里需要注意的是 ApplicationContext 并没有重复实现 BeanFactory 的功能,而是将请求代理给内部持有的 BeanFactory)。 GenericApplicationContext 中就将对容器的请求,代理给了 DefaultListableBeanFactory 这一 BeanFactory 实现。 除此之外,ApplicationContext 继承了 EnvironmentCapable 表明它具有操纵 Environment 的能力(Environment getEnvironment();); 继承了 ResourcePatternResolver 表明它能够解析、加载资源文件(getResources、getResource); 继承了 MessageSource 表明它能够解析消息,处理参数化、国际化等; 继承了 ApplicationEventPublisher 表明它能够发布相关事件(publishEvent)。
ApplicationContext 自身只定义了少数几个方法,例如 getId、getApplicationName、getDisplayName、getAutowireCapableBeanFactory 等。 ApplicationContext 的直接子接口包括两个:ConfigurableApplicationContext 和 WebApplicationContext。
接下来,我来完成前面留下的一个任务,即与大家一块学习下 AbstractApplicationContext 对 ConfigurableApplicationContext#refresh 方法的实现。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
/**
* 主要是设置 active/closed 状态位,startDate 统计信息,
* 初始化 PropertySource、验证 required property 等
*/
// Prepare this context for refreshing.
prepareRefresh();
/**
* 刷新内部的 BeanFactory,实际是 DefaultListableBeanFactory 对象。
* 如果存在旧的 BeanFactory,则关闭后,重新创建、配置并加载 BeanDefinition
*/
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/**
* 对 BeanFactory 进行预处理,包括:
* 1. 设置类加载器
* 2. 设置 BeanPostProcessor:ApplicationContextAwareProcessor、ApplicationListenerDetector 和 LoadTimeWeaverAwareProcessor 等。
* 3. 注入 environment、systemProperties 等对象
* 这里是官网对比 ApplicationContext 与 BeanFactory 优劣时的一项内容 “Automatic BeanPostProcessor registration”
* ApplicationContext 相比 BeanFactory 会做更多的事,开发时更推荐使用 ApplicationContext,除非你有非用 BeanFactory 不可的理由。
*/
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
/**
* 记录启动时间
*/
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
/**
* 注册 BeanPostProcessor
*/
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
/**
* 这里会触发容器预实例化所有的单例 Bean 对象
*/
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
/**
* 容器的初始化完成,通知其他关注容器事件的模块,容器初始化(刷新)完成
*/
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException 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...
resetCommonCaches();
contextRefresh.end();
}
}
}
复制代码
接下来,我会特别介绍下 ApplicationContextAwareProcessor 这个 BeanPostProcessor 实现。 它与 AbstractAutowireCapableBeanFactory 关系比较密切。 AbstractAutowireCapableBeanFactory 中定义了两个集合,ignoredDependencyTypes 和 ignoredDependencyInterfaces,并实现了 ConfigurableListableBeanFactory#ignoreDependencyType 和 ConfigurableListableBeanFactory#ignoreDependencyInterface 两个方法,分别向两个集合中添加元素。 这两个集合仅在 AbstractAutowireCapableBeanFactory#isExcludedFromDependencyCheck 方法中使用,主要作用是判断某个特定的 property 是否应当在依赖检查中被排除。
protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
return (AutowireUtils.isExcludedFromDependencyCheck(pd) || /** 忽略 CGLIB 定义的 property */
this.ignoredDependencyTypes.contains(pd.getPropertyType()) || /** 忽略 ignoredDependencyTypes 集合中包含的类型 */
AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces)); /** 如果 property 的设置方法在 ignoredDependencyInterfaces 中有定义,则忽略 */
}
复制代码
isExcludedFromDependencyCheck 方法被两个地方调用:
通过上面的介绍可以得出,这两个集合在填充类属性(即解析依赖并注入依赖)时使用。
ApplicationContextAwareProcessor 是一个 BeanPostProcessor,简单来说就是 Bean 容器在创建、实例化一个托管 Bean 时,会在一定的时机调用其中的回调方法。 ApplicationContextAwareProcessor 负责处理多个 Aware 接口,在 Bean 实例化后,调用它的 setXXX 方法:
基于 Spring IoC 容器构建的应用一般包括两部分,第一部分是业务对象,一般是指托管在容器中的 Java 类; 第二部分是配置元信息,这部分信息告诉 Spring IoC 容器如何实例化、配置、装配托管的 Bean。 配置元信息可以有多种形式:
如无特殊说明,本节中涉及的 IoC 容器指 ApplicationContext 接口的不同实现。
/** 使用 XML 作为配置文件 */
final ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
/** 使用 Java 类作为配置文件 */
final ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
/** 使用 Groovy 文件作为配置文件 */
final ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
复制代码
/** 使用容器 */
final Object foo = context.getBean("foo");
复制代码
本节中,我将介绍使用 Java 类做为配置文件时常用的注解。 相信大部分人对这部分内容都比较熟悉,因而我不会过多的展开。你也可以选择跳过本节的内容。
@Autowired 是最常见的一个注解,它可以标注在构造器方法、setter 方法、其他方法,甚至可以直接注解在对象属性上。
AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata
@Autowired 标注的地方,可以称之为依赖注入点(injection points)。 而且,默认是通过类型来进行注入的。注意看下面的示例:
@Autowired
private Bar[] bars;
复制代码
会收集容器中所有的 Bar 类型的 Bean,组合成数组,注入到 bars 中。 上述机制,除了数组类型,同样适用于 Set
默认情况下,@Autowired 定义的注入点,默认是必需依赖;如果依赖非必需(或可选的),则可以通过 @Autowired(required = false)。 必需依赖和非必需依赖的区别在于,当依赖注入时,容器中找不到必需依赖时会抛异常,导致容器退出;而非必需依赖找不到时,只会忽略。 非必需依赖的另一种方式(Java 8 及以上版本),是通过 Optional 类,例如:
@Autowired
public void setBar(Optional bar) { }
复制代码
另外一种方式是 JSR-305 定义的 @Nullable:
@Autowired
public void setBar(@Nullable Bar bar) { }
复制代码
@Resource 与 @Autowired 作用一样,不同的是它由 JSR-250 定义,并且定义的注入点是按照 BeanName 注入的,而非按照类型。 @Inject 类似,由 JSR-330 定义,默认按照类型注入。
按照类型注入时,会遇到同类型多个候选对象的情况。 @Primary 的作用是在自动装配时,从众多候选者中指定一个优先级最高的候选者。 @Qualifier 的作用类似,用在自动装配时,不过能够提供粒度更细的控制。
前面提到的注解,注入的都是其他 Bean,即依赖类型为复合类型。 如果要注入的值是简单类型,例如字符串,可以使用 @Value。 它的数据来源可以是 Environment、SystemProperties 等中的变量,也可以是 @PropertySource 指定的外部配置文件中的变量。 而且,@Value 支持 SpEL 表达式。
JSR-250 还定义了 Bean 的生命周期回调 @PostConstruct 和 @PreDestroy,作用类似于 XML 配置中的 "init-method" 和 "destroy-method"。
Spring 中,Bean 的默认作用范围是 Singleton,可以通过 @Scope 修改它的实际作用范围。
@Component 及它的子类型 @Service、@Controller、@Repository、@Configuration 被称之为 "Stereotype Annotations"(样板注解)。 Spring 中提供了自动扫描或检测的机制,来发现上述样板注解标注的类,并创建对应的 Bean 对象。这个机制称为 "Component Scan"(组件扫描)。 组件扫描通过 @ComponentScan 来配置,作用与 XML 配置中的
JSR-330 中定义了 @Named、@ManagedBean,与 @Component 作用一样。
@Bean 注解一般可以用在 @Configuration 或其他 @Component 类中,用来定义 Bean。
一般来说,用户不需要通过继承 ApplicationContext 实现的方式扩展容器的功能。 Spring IoC 容器在设计的时候,预留了扩展点给用户,以便用户实现特有的业务功能。 接下来,我将盘点一下 Spring 预留的扩展点。
首先,最为人熟知或者最常见的扩展点是 BeanPostProccessor 接口。 它共定义了两个方法:
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
复制代码
这两个方法的调用时机发生在 AbstractAutowireCapableBeanFactory#initializeBean 中,即 Spring 创建 Bean 实例过程三阶段中的最后一个阶段。
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) { }
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
复制代码
AppliationContext 实现类会自动的查找容器中所有 BeanPostProcessor 实现,并将它们注册到 BeanFactory 中。
// org.springframework.context.support.AbstractApplicationContext#refresh
registerBeanPostProcessors(beanFactory);
// org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
复制代码
另外一个扩展点是 BeanFactoryPostProcessor 接口,它只定义了一个方法:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
复制代码
调用时机发生在 ApplicationContext 容器刷新时,即 AbstractApplicationContext#refresh 中。
// org.springframework.context.support.AbstractApplicationContext#refresh
invokeBeanFactoryPostProcessors(beanFactory);
// org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
复制代码
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 中,会先执行 BeanDefinitionRegistryPostProcessor(它是 BeanFactoryPostProcessor 的一个子类),再执行其他的 BeanFactoryPostProcessor。 ConfigurationClassPostProcessor 是 BeanDefinitionRegistryPostProcessor 的一个实现类,负责处理 @Configuration 标注的类。
再举个例子,PropertySourcesPlaceholderConfigurer 也实现了 BeanFactoryPostProcessor 接口,负责处理 BeanDefinition 中的“${...} ”占位符。 BeanFactoryPostProcessor 的调用时机发生在所有的单例 Bean 被创建之前,而且它操作的对象是 BeanDefinition。 所以,如果你有在 Spring 创建 Bean 之前做某些特定逻辑的需求,可以考虑实现自己的 BeanFactoryPostProcessor。
最后一个扩展点是 FactoryBean 接口,即工厂 Bean。 这个接口其实比较容易理解,它里面最重要的方法就是 FactoryBean#getObject 方法。 当通过 "&" + "beanName" 方式从容器中获取 Bean 时,获得的是 FactoryBean 对象(若有)。 如果仅通过 "beanName" 从容器中获取,当存在 BeanFactory 对象时,会调用它的 getObject 方法来创建一个对象。 当某个 Bean 的创建过程非常复杂时,可以通过自定义 FactoryBean 的方式来完成 Bean 的创建。
希望今天的内容能对你有所帮助。
页面更新:2024-05-09
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号