Spring源码---ApplicationContext的抽象实现
导语
接着上一篇,继续看看spring源码,再菜也要坚持看完!
ConfigurationApplicationContext
CAC接口中的属性和方法:
从上图可以看出,属性和方法基本都是对上下文的配置和系统自带bean 的名字,值得注意的是getBeanFactroy()方法与AC接口的方法同名,同参,返回值类型不同但具有继承关系。还有就是refresh()方法,看了看方法上的注释,大致是想我们使用这个方法通过配置文件来加载或来刷新 persistent representation (大概就是配置的bean吧)。
AbstractApplicationContext
AAC是第一个实现spring上下文接口的抽象类,由于接口中累积了大量的方法,本着单一职责的设计思路,把功能细化,然后通过代理模式分配出去,而自身主要是对CAC和AC本身的方法进行实现。我们暂且忽略被代理出去的方法,因为在本类中也无法看出其具体实现,先看看类中的属性:
可以看出现在spring的上下文已经具备一些实质性的东西了,也就是上面的这些属性,实现的接口也基本基于这些属性的操作方法。由于类中方法数太多,绝大部分分都是通过代理或组合模式来实现的,就不进行截图也暂且丢一边,主要看refresh()方法的实现。
// Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // 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(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh();
上面是refresh()方法的主要代码,里面调用的方法名称跟其目的是一致的,perpareRefresh()是设置active,closed,startTime属性和初始化earlyApplicationEventj集合用于准备工作。由于BeanFactory使用是抽象代理,并没有明确到具体实例,obtainFreshBeanFactroy()则是告诉子类,要开始refresh了你得准备一下并把BeanFactory返回给我。从子类中得到BeanFactory后,perpareBeanFactory()开始对BeanFactory添加一些标准化设置及注册系统bean,截取方法中的注释。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. // Configure the bean factory with context callbacks. // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean.; // Register early post-processor for detecting inner beans as ApplicationListeners. // Detect a LoadTimeWeaver and prepare for weaving, if found. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { // Set a temporary ClassLoader for type matching. } // Register default environment beans. }
到这里,BeanFactory的准备工作和初始化设置基本完成了,spring的容器也就已经准备好了,对于容器这个概念,也比较抽象,我也只是简单的将其理解为里面存放了很多类的实例对象,当你需要的时候就只需要去容器中拿,显然这些对象应该是无状态的。容器存在与context中的,context则是借助容器来实现对对象实例的共享管理。
BeanFactory创建好了,我们还需要往里面注册processors,用于对bean进行操作处理,毕竟工厂是工厂,有工人之后工厂才能发挥其能力。同时,消息资源和事件监听和推送也是属于共享且无状态的对象,也可以初始化后放入容器中,这些操作便在registerBeanPostProcessors(),initMessageSource(),initApplicationEventMulticaster()。
/** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for registering special * BeanPostProcessors etc in certain ApplicationContext implementations. * @param beanFactory the bean factory used by the application context */ protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { }
postProcessBeanFactory()方法并没有一行代码,注释中也表明,在BeanFactory标准化后允许子类覆盖这个方法,来使BeanFactory能操作自定义或特殊的Bean。
/** * Template method which can be overridden to add context-specific refresh work. * Called on initialization of special beans, before instantiation of singletons. * <p>This implementation is empty. * @throws BeansException in case of errors * @see #refresh() */ protected void onRefresh() throws BeansException { // For subclasses: do nothing by default. }
onfresh()方法也是空,这部分也将陪分配到子类中,具体解释看注释吧。
protected void registerListeners() { // Register statically specified listeners first. // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! // Publish early application events now that we finally have a multicaster... } protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. // Register a default embedded value resolver if no bean post-processor // (such as a PropertyPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. // Stop using the temporary ClassLoader for type matching. // Allow for caching all bean definition metadata, not expecting further changes. // Instantiate all remaining (non-lazy-init) singletons. } protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). // Initialize lifecycle processor for this context. // Propagate refresh to lifecycle processor first. // Publish the final event. // Participate in LiveBeansView MBean, if active. }
终于,在这个时候知道注释有多么的重要,特别是在大型的应用中,功能将被拆到多个类,多个方法中,真的无法凭记忆去感觉。在子类的onRefresh()执行之后,BeaFactory的工作也收尾了。也许还记得earlyApplicationEvent这个属性,因为在创建前没有消息的发布者(muticaster),context创建前的事件都被存到该集合,直到registerListener()后,再将其发布。finishBeanFactoryInitialization()则是开始实例话bean了,finishRefresh()则是清空resource case,classLoader等缓存。最后发布一个ContextRefreshedEvent事件,宣布上下文创建或刷新已经完成了。。(掌声!!)
AbstractRefreshableApplicationContext
ARAC继承自AAC,对一个R,也代表了它多一个Refreshable属性。但是在AAC中也有refresh,只不过AAC中的refresh只是对context的标准化,而ARAC是刷新BeanFactroy。
从上图看,ARAC完成了一个关键的操作,创建了BeanFactory,终于看到了BeanFactory的真身了,还为期定义了两个allow属性:
protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
有了BeanFactory后,ARAC就得完成其父亲AAC的叮嘱,为AAC先刷新好BeanFactory(还记得// Tell the subclass to refresh the internal bean factory. 这个注释吗?)。
@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); } }
以上便是刷新BeanFactory的操作,里面没有注释是不是说这很j简单?确实,就连核心操作loadBeanDefinition都是抽象方法。好吧,我们也跳过这个类,感谢它带来的BeanFactoy和定义的几个刷新方法,还有两个allowsh属性。
AbstractRefreshableConfigApplicationContext
好吧,现在的context可以有自定义的配置文件了。
但还是注意一下,ARCAC还实现了BeanNameAware,InitializingBean两个接口。
/** * Triggers {@link #refresh()} if not refreshed in the concrete context's * constructor already. */ @Override public void afterPropertiesSet() { if (!isActive()) { refresh(); } }
上面是InitializingBean中的方法,大致是触发自动刷新,目前还没看见具体触发机制的实现。
AbstractXmlApplicationContext
AXAC是对context的最后一层抽象,实现了其父类最后一个为实现的抽象方法:
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
因为配置文件加载的次数有限,loadBeanFactory()也是直接new 一个对象来完成使命。现在的AXAC中并没有任何抽象方法,按理可以写成一个普通类,依旧定义成抽象类也决定了AXAC无法被实例化,设计的目的为何?
结尾
到此,从定义的接口到全部的实现,context这个巨大的角色框架基本已经清楚了,我们也看到了巨型角色构建的设计艺术。大致上从AAC对职责的划分,分配到各个代理中,再定义了一个总体的refresh对策,把核心的自定义配置加载(obtainFreshBeanFactory()),自定义刷新BeanFactory (onRefresh())功能抽象出去,分别让ARCAC和ARAC实现,最后由AXAC统一大业,不得不佩服AAC抽象类的设计。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python开发环境pipenv
使用pipenv(官方推荐) pipenv只是一个工具,我们用这个工具来创建虚拟环境;我们用pipenv来创建一个虚拟环境,这个虚拟环境是和项目绑定的,也就是我们每创建一个项目就要创建一个虚拟环境 安装: pip install pipenv 为项目安装独立的虚拟环境 # 进入项目相应的目录以后 pipenv install image.png image.png 启动pipenv 启动 # 在项目目录下执行 pip shell image.png 退出 exit image.png 安装包 pipenv install flask 卸载包 pipenv uninstall flask image.png 查看包之间的依赖关系 pipenv graph image.png 查看虚拟环境的路径 image.png 安装各种包,比如Flask pipenv install flask
- 下一篇
JavaWeb开发之详解Servlet及Servlet容器
自JavaEE诞生伊始,Servlet容器和Servlet技术,就构成了JavaEE应用的核心,配合其它组件,它们完善了Java企业级开发的全套解决方案。小到一个静态博客网站,大到分布式的集群应用,都离不开Servlet底层的支持。大约从Java 5开始,Java企业级开发就分为了两个不同的方向,一个是基于EJB、JSF、JPA等为主的传统Java企业级系统开发方案,另一套则是基于Struts、Hibernate、Spring、Spring MVC、MyBatis等为主JavaWeb开发模式。时至今日,移动互联网的蓬勃发展下,产生了一大批的电商、新零售、在线游戏、社交网站等各式应用。JavaWeb在时代洪流中反而得到越来越大的发展:分布式、集群、中间件、大数据……给Java带来了蓬勃生机。 而这些互联网应用的基础,都有Servlet的影子。那么Servlet到底是什么??? 在StackOverflow上就有这么个问题,题主搞了很久都搞不明白Servlet到底是什么,希望有人能用浅显直白的语言一语中的地回答他。排名第一的高票答案是这么说的: A servlet is simply a ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Hadoop3单机部署,实现最简伪集群
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池