前面两篇文章,已经对ApplicationContext的大部分内容做了介绍,包括国际化,Spring中的运行环境,Spring中的资源,Spring中的事件监听机制,还剩唯一一个BeanFactory相关的内容没有介绍,这篇文章就来介绍BeanFactory,这篇文章介绍,关于ApplicationContext相关的内容总算可以告一段落了。本文对应官网的1.16和1.15小节
前面也提到了ApplicationContext继承了BeanFactory接口,其继承关系如下:
下面我们直接进入BeanFactory相关内容的学习
BeanFactory
接口定义
可以看到BeanFactory接口主要提供了查找bean,创建bean(在getBean调用的时候也会去创建bean),以及针对容器中的bean做一些判断的方法(包括是否是原型,是否为单例,容器是否包含这个名词的bean,是否类型匹配等等)
继承关系
接口功能
作为BeanFactory的直接子接口有三个,分别为:
HierarchicalBeanFactory,ListableBeanFactory,AutowireCapableBeanFactory。
- HierarchicalBeanFactory
HierarchicalBeanFactory对顶层的BeanFactory做了扩展,让其具有了父子层级关系
2. ListableBeanFactory
从上面的方法中可以看出,相对于BeanFactory,ListableBeanFactory提供了批量获取bean的方法
3. AutowireCapableBeanFactory
可以看到这个类中的方法都和装配bean,配置bean相关。另外还有一系列专门处理注入的方法,可以看到接口有一个很大的作用就是对一些不受Spring管理的bean,也为其提供依赖注入的功能。例如:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Appconfig.class);
AutowireCapableBeanFactory beanFactory = ac.getBeanFactory();
DmzService bean = beanFactory.createBean(DmzService.class);
// 打印:com.xxl.service.IndexService@17d99928
bean.test();
// 抛出NoSuchBeanDefinitionException
// ac.getBean(DmzService.class);
}
}
@Configuration
@ComponentScan("com.xxl.service")
public class Appconfig {
}
//DmzService没也被放入容器中
public class DmzService {
@Autowired
IndexService indexService;
public void test(){
System.out.println(indexService);
}
}
// 被容器所管理
@Component
public class IndexService {
}
在上面的例子中,DmzService没有被容器管理,所以在调用ac.getBean(DmzService.class)会抛出NoSuchBeanDefinitionException,但是我们可以看到,indexService被注入到了DmzService中。
4. ConfigurableBeanFactory
可以看到这个接口继承了HierarchicalBeanFactory,并基于它扩展了非常多的方法。除了继承了HierarchicalBeanFactory,还继承了一个SingletonBeanRegistry,其接口定义如下:
5. ConfigurableListableBeanFactory
所有接口的集大成者,拥有上面所有接口的功能
6. AbstractBeanFactory
实现了大部分的方法,其中最终的实现为getBean()/doGetBean()方法的实现,提供了模版。其实createBean抽象方法,还是子类去实现的 //... isSingleton(String name) / isPrototype(String name) / containsBean(String name) 也能实现精准的判断了。
其中,它自己提供了三个抽象方法,子类必要去实现的
7. AbstractAutowireCapableBeanFactory
- 实现了AbstractBeanFactory中的createBean方法,能够创建一个完全的Bean
- 实现了AutowireCapableBeanFactory,能对Bean进行实例化,属性注入,已经细粒度的生命周期管理
8. DefaultListableBeanFactory
没什么好说的了,最牛逼的一个BeanFactory,拥有上面的一切功能,额外的它实现了BeanDefinitionRegistry接口,具备注册管理BeanDefinition的功能
ApplicationContext体系汇总
ApplicationContext整体可以分为两个体系,一个就是web体系,另一个就是非web体系
非web体系
- ConfigurableApplicationContext
ApplicationContext接口中的方法比较简单,之前我们也一一分析它继承的接口以及它所具备的功能。并且ApplicationContext接口的方法都是只读的,不能对当前容器做任何改变,而ConfigurableApplicationContext接口在ApplicationContext的基础上增加了很多进行配置的方法,比如添加事件监听器,添加后置处理器等等。
2. AbstractApplicationContext
这个类实现了ConfigurableApplicationContext,具备了上面接口大部分功能, 但是他没有实现getBeanFactory()方法,这个方法留待子类实现,所以它自己没有实际的管理Bean的能力,只是定义了一系列规范
3. AbstractRefreshableApplicationContext
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
// 碰到重复的Bean时,是否允许覆盖原先的BeanDefinition
@Nullable
private Boolean allowBeanDefinitionOverriding;
// 是否允许循环引用
@Nullable
private Boolean allowCircularReferences;
// 默认持有一个DefaultListableBeanFactory
@Nullable
private DefaultListableBeanFactory beanFactory;
// 对内部工厂进行操作时所采用的锁
private final Object beanFactoryMonitor = new Object();
public AbstractRefreshableApplicationContext() {
}
public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {
super(parent);
}
public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
}
public void setAllowCircularReferences(boolean allowCircularReferences) {
this.allowCircularReferences = allowCircularReferences;
}
// 刷新Bean工厂,如果当前上下文中已经存在一个容器的话,会先销毁容器中的所有Bean,然后关闭Bean工厂
// 之后在重新创建一个DefaultListableBeanFactory
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
@Override
protected void cancelRefresh(BeansException ex) {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory != null) {
this.beanFactory.setSerializationId(null);
}
}
super.cancelRefresh(ex);
}
@Override
protected final void closeBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory != null) {
this.beanFactory.setSerializationId(null);
this.beanFactory = null;
}
}
}
protected final boolean hasBeanFactory() {
synchronized (this.beanFactoryMonitor) {
return (this.beanFactory != null);
}
}
// 复写了getBeanFactory,默认返回的是通过createBeanFactory创建的一个DefaultListableBeanFactory
@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;
}
}
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
.......
// 提供了一个抽象的加载BeanDefinition的方法,这个方法没有具体实现,不同的配置方式需要进行不同的实现,
// 到这里,配置的方式不能确定,既可能是以XML的方式,也可能是以java config的方式
// 另外配置文件的加载方式也不能确定
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException,
}
可以看到这个类可进一步对上下文进行配置,例如进行是否开启循环引用,是否允许进行BeanDefinition的覆盖等等。另外它所提供的一个重要的功能就是使容器具备刷新的功能,换言之,凡是需要刷新功能的容器都需要继承这个类。
4. AbstractRefreshableConfigApplicationContext
5. AbstractXmlApplicationContext
可以看到这个类进一步对配置的加载做了明确,首先明确配置的类型为XML,第二步明确了要通过getConfigResources方法来加载需要的配置资源,但是并没有对这个方法做具体事项,因为对于Resource的定义,可能是通过classpath的方法,也可能是通过URL的方式,基于此又多了两个子类
- ClassPathXmlApplicationContext,从classpath下加载配置文件
- FileSystemXmlApplicationContext,基于URL的格式加载配置文件
6. GenericApplicationContext
这个类已经部署抽象类了,可以直接使用它。但是这个类有一个很大的缺点,它不能去读配置,需要手动去指定读取的方式和位置。其实从上下文中的分析可以看出,从AbstractApplicationContext到AbstractXmlApplicationContext一步步明确了配置的加载方式,Spring通过这种类的继承将配置的加载分了很多层,可以从AbstractXmlApplicationContext的子类开始从任意以及进行扩展
而GenericApplicationContext只实现了上下文的基本功能,并没有对配置做任何约束,所以在使用它时需要手动往其注入BeanDefinition。这样虽然灵活,但是很麻烦,如果我们使用GenericApplicationContext可能需要进行下面这样的操作
GenericApplicationContext ctx = new GenericApplicationContext();
//使用XmlBeanDefinitionReader,这个地方我们甚至可以自己定义解析器,不使用Spring容器内部的
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
//加载ClassPathResource
xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
//调用Refresh方法
ctx.refresh();
//和其他ApplicationContext方法一样的使用方式
DmzService myBean = (DmzService) ctx.getBean("myBean");
平常的开发基本用不到这东西
7. AnnotationConfigApplicationContext
通过AnnotationConfigApplicationContext注册配置类,用ClassPathBeanDefinitionScanner扫描配置类上申明的路径,得到所有的BeanDefinition。然后其余的没啥了。这个我们经常使用,因为不需要XML文件了,使用@Configuration配置类即可,更加的方便
web体系
- WebApplicationContext
定义了一堆常量,以及一个方法,约束了所有的web容器必须能返回一个Servlet的上下文(ServletContext)
2. ConfigurableWebApplicationContext
可以看到使用这个类能指定上下文配置加载的位置
3. AbstractRefreshableWebApplicationContext
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
.......
}
首先可以看到这个类继承了AbstractRefreshableConfigApplicationContext,代表它需要从指定的位置加载配置,其次它实现了ConfigurableWebApplicationContext,所以它具有web容器的属性
4. XmlWebApplicationContext
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
// .......
@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
}
进一步指定了配置文件的加载形式
- 需要加载XML类型配置
- 对于根容器,加载路径为/WEB-INF/applicationContext.xml
- 对于子容器,加载路径为/WEB-INF/+'namespace'+.xml,比如常用的dispatchServlet.xml
5. AnnotationConfigWebApplicationContext
指定了以注解的方式配置web容器
6. GenericWebApplicationContext
类比GenericApplicationContext,没有指定配置相关的任何东西,全手动
总结
从上面我们可以看到,整个一套体系下来不可谓不庞大,Spring在单一职责可以说做到了极致,不论是按功能分,比如HierarchicalBeanFactory,ListableBeanFactory,AutowireCapableBeanFactor就是按照不同功能拆分,或者是按照功能实现的层级划分,比如上面说到的配置文件的加载机制。对类之间的关系进行了明确的分层,代表了整个体系会具备非常强大的扩展性,我们可以在每一步进行之间的扩展。这是让Spring能组件化开发,可插拔,变得如此优秀,普适的重要原因。
到此,关于ApplicationContext相关的内容终于可以告一段落了,代表着IOC已经结束了,粗略看了下官网,接下来还剩数据绑定,数据效验,类型转换以及AOP,任重而道远,加油吧!~
标签:ApplicationContext,beanFactory,Spring,bean,源码,new,public,加载 From: https://blog.51cto.com/u_15668812/7323654