提及Spring中的灵魂伴侣难道不是BeanFactory与FactoryBean吗?ta们两个不只长相类似,在面试题目中更是如影随行,成双成对。然而事实上两者的关系就像生命中的过客,只是匆匆一眼,便相忘于江湖。
不过FactoryBean并不孤单,远处的ObjcetFactory遥遥相望,本文中并不许备详细解析这两个接口,不过读者能够把他们两个理解为指定类型Bean的孵化器,咱们能够经过这两个接口改变Bean的初始化行为。可是两者仍是有很大区别的。html
平常工做中咱们经常将BeanFactory称为容器,而将ApplicationContext称为上下文。不知你们究竟有没有思考过两者之间的关系。Spring Aware接口家族一文中我曾详细阐释过如何获取当前运行环境中的BeanFactory、ApplicationContext,咱们不妨在代码中找寻答案。java
package com.spring.container;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.spring.container")
public class ContainerConfig {
}
复制代码
package com.spring.container;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/** * @Author: Raphael */
@Component
public class SpringIoc implements BeanFactoryAware, ApplicationContextAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.err.println(System.identityHashCode(beanFactory));
System.out.println(beanFactory.getClass().getName());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.err.println(System.identityHashCode(applicationContext));
System.out.println(applicationContext.getClass().getName());
}
}
复制代码
package com.spring.container;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/** * @Author: Raphael */
public class MainContainer {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ContainerConfig.class);
context.close();
}
}
复制代码
敏锐的人其实已经发现了矛盾,认知中Spring的根容器应该有且只有一个才合理。可是这分明就是两个没有什么关联的对象啊。Spring官方文档如此论述两者的关系:面试
简而言之,BeanFactory提供了配置框架和基本功能,ApplicationContext增长了更多针对企业的功能。ApplicationContext是BeanFactory的一个完整的超集。spring
按照官方的解释:两者是一个包含与被包含的关系,那么在ApplicationContext中咱们能够得到根容器吗?
上帝说:要有光,因而getAutowireCapableBeanFactory()就来了。设计模式
package com.spring.container;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/** * @Author: Raphael */
@Component
public class SpringIoc implements BeanFactoryAware, ApplicationContextAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.err.println(System.identityHashCode(beanFactory));
System.out.println(beanFactory.getClass().getName());
}
// 直接打印两个对象的比对结果
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
AutowireCapableBeanFactory factory =
applicationContext.getAutowireCapableBeanFactory();
System.err.println(factory.hashCode());
System.out.println(factory.getClass().getName());
System.out.println("两者相等吗: " + (factory == beanFactory));
}
}
复制代码
验证结果彻底支持官方说明。app
官方对他如此定义:框架
Spring的{@link ConfigurableListableBeanFactory},{@link BeanDefinitionRegistry}的默认实现
成熟的bean工厂
基于bean定义元数据,可经过后处理器进行扩展ide
台前光亮的是BeanFactory,负重前行的倒是DefaultListableBeanFactory,明明是三我的的电影,我却始终不能有姓名。那么DefaultListableBeanFactory的对象是什么时候产生的呢?一个新的问题又萦绕在个人心头。答案其实与IOC容器的初始化密不可分,我在这里不详叙了。咱们只简单的剖析一下DefaultListableBeanFactory产生对象的心路历程。
咱们在MainContainer中调用了以下构造方法:post
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
复制代码
由于AnnotationConfigApplicationContext继承了GenericApplicationContext,因此父类的的构造方法也会同时调用,容器对象就在此时诞生。ui
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
复制代码
而后refresh()调用obtainFreshBeanFactory()。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
复制代码
getBeanFactory()是AbstractApplicationContext定义的抽象方法。又由GenericApplicationContext实现。
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
复制代码
这里其实就是将本身构造方法产生的对象返回给AnnotationConfigApplicationContext。追踪到这一层的时候,容器对象的身世之谜才终于被咱们揭开。其实ApplicationContext之因此有Beanfactory能力就是由于有关容器的操做他都委托给本身内部的容器对象了。举个例子:
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, requiredType);
}
复制代码
这里实际上他并无对此方法有详细的实现,而是经过getBeanFactory()获取自身内部的容器对象,而后交由ta实现。 如今脉络应该足够清晰了。Spring源码是设计模式的集大成者,这里其实运用的就是组合模式。
其实官方有他们两者的总结
org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基础。BeanFactory 接口提供了一种高级配置机制,可以管理任何类型的对象。 ApplicationContext 是其子接口。
增长了如下特性:
Spring官方文档,真的不许备去看看嘛?
最后: 花长好,月长圆,人长寿