欢迎大家来到IT世界,在知识的湖畔探索吧!
继承层次图概览
使用IDEA的继承层次工具生成如下的图(选中ApplicationContext –> Ctrl+H):
(温馨提示:双击可查看高清大图)
从上图能很清楚的看出,ApplicationContext的子接口分为两个部分:
- ConfigurableApplicationContext:大部分的应用上下文都实现了该接口
- WebApplicationContext:在web应用程序中使用
ConfigurableApplicationContext分析
从上面的类的继承层次图能看到,ConfigurableApplicationContext是比较上层的一个接口,该接口也是比较重要的一个接口,几乎所有的应用上下文都实现了该接口。该接口在ApplicationContext的基础上提供了配置应用上下文的能力,此外提供了生命周期的控制能力。先看一下该接口的继承关系图(为了更加简洁,去掉了ApplicationContext继承的接口):
(温馨提示:双击可查看高清大图)
Closeable接口用于关闭应用上下文,释放所有的资源和锁,这也包括摧毁所有缓存的单例的bean,常见的try-with-resources用法如下,执行完try体中的代码后会自动的调用close方法:
try (ConfigurableApplicationContext cac = ...) { // 编写代码 ... }
欢迎大家来到IT世界,在知识的湖畔探索吧!
Lifecycle定义了启动/停止生命周期的控制的一些方法,其中的方法如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!void start(); // 启动组件 void stop(); // 停止组件 boolean isRunning(); // 组件是否正在运行
接下来看一下ConfigurableApplicationContext中的方法:
void setId(String id); // 设置应用上下文唯一的id void setParent(ApplicationContext parent); // 设置应用程序上下文的父级 void setEnvironment(ConfigurableEnvironment environment); // 设置应用上下文的环境 ConfigurableEnvironment getEnvironment(); // 获取应用上下文的环境 // 添加一个新的BeanFactoryPostProcessor void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor); // 添加应用程序监听器 void addApplicationListener(ApplicationListener<?> listener); // 添加协议解析器,可能会覆盖默认的规则 void addProtocolResolver(ProtocolResolver resolver); // 加载或者刷新配置 void refresh() throws BeansException, IllegalStateException; // 向JVM runtime注册一个关闭钩子,JVM关闭时关闭这个上下文 void registerShutdownHook(); // 应用程序上问下是否是激活状态 boolean isActive(); // 获取应用上下文内部的bean factory ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
上面的这些方法基本上是提供了对某些特性的实现进行支撑的方法。
看了这么多方法,下面看一下ApplicationContext的抽象的实现。
AbstractApplicationContext
AbstractApplicationContext是ApplicationContext接口的抽象实现,这个抽象类仅仅是实现了公共的上下文特性。这个抽象类使用了模板方法设计模式,需要具体的实现类去实现这些抽象的方法。对相关接口的实现如下:
- ApplicationContext接口的实现
- ConfigurableApplicationContext接口的实现
- BeanFactory接口的实现
- ListableBeanFactory接口的实现
- HierarchicalBeanFactory接口的实现
- MessageSource接口的实现
- ResourcePatternResolver的实现
- Lifecycle接口的实现
本文不会详细的讲解这个类中的具体的实现细节,后面会有更加的详细的介绍。下面看下里面的抽象方法:
欢迎大家来到IT世界,在知识的湖畔探索吧!// 刷新BeanFactory,用于执行实际的配置加载,该方法在其他的初始化工作之前被refresh()方法调用 protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException; // 关闭BeanFactory,用于释放内部使用的BeanFactory· protected abstract void closeBeanFactory(); // 获取内部使用的BeanFactory public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
那么对需要实现的方法经过抽象后,只剩下少量的需要子类去实现的方法。
GenericApplicationContext
GenericApplicationContext继承自AbstractApplicationContext,是为通用目的设计的,它能加载各种配置文件,例如xml,properties等等。它的内部持有一个DefaultListableBeanFactory的实例,实现了BeanDefinitionRegistry接口,以便允许向其应用任何bean的定义的读取器。为了能够注册bean的定义,refresh()只允许调用一次。常见的使用如下:
GenericApplicationContext ctx = new GenericApplicationContext(); XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx); xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml")); PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx); propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties")); ctx.refresh(); MyBean myBean = (MyBean) ctx.getBean("myBean"); ..
这个类的实现没有太多需要注意的地方,需要注意的有两点:
- 内部使用的DefaultListableBeanFactory的实例,提供了一些方法来配置该实例,例如是否允许bean定义的覆盖、是否允许bean之间的循环应用等等。
- 该类实现了BeanDefinitionRegistry,bean的定义注册。以便能通过BeanDefinitionReader读取bean的配置,并注册。BeanDefinitionRegistry接口的实现是直接使用内部的DefaultListableBeanFactory的实例。
GenericXmlApplicationContext
GenericXmlApplicationContext继承自GenericApplicationContext,内置了对XML的支持。它非常的方便和灵活,是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext的一种替代品。可以发现,它的内部有一个XmlBeanDefinitionReader的实例,专门用于处理XML的配置。
StaticApplicationContext
StaticApplicationContext继承自GenericApplicationContext,主要用于编程式的注入bean和消息,而不是从外部的配置源读取bean的定义。主要是在测试时非常有用。通过阅读源代码可以看到,它的内部有一个StaticMessageSource的实例,使用addMessage方法添加消息。每次在编程式的注入bean时,都会创建一个GenericBeanDefinition的实例。
ResourceAdapterApplicationContext
ResourceAdapterApplicationContext继承自GenericApplicationContext,是为JCA(J2EE Connector Architecture)的ResourceAdapter设计的,主要用于传递BootstrapContext的实例给实现了BootstrapContextAware接口且由spring管理的bean。覆盖了postProcessBeanFactory方法来实现此功能。
GenericGroovyApplicationContext
GenericGroovyApplicationContext继承自GenericApplicationContext,实现了GroovyObject接口以便能够使用点的语法(.xx)取代getBean方法来获取bean。它主要用于Groovy bean的定义,与GenericXmlApplicationContext一样,它也能解析XML格式定义的bean。内部使用GroovyBeanDefinitionReader来完成groovy脚本和XML的解析。
AnnotationConfigApplicationContext
AnnotationConfigApplicationContext继承自GenericApplicationContext,提供了注解配置(例如:Configuration、Component、inject等)和类路径扫描(scan方法)的支持,可以使用register(Class<?>… annotatedClasses)来注册一个一个的进行注册。实现了AnnotationConfigRegistry接口,来完成对注册配置的支持,只有两个方法:register和scan。内部使用AnnotatedBeanDefinitionReader来完成注解配置的解析,使用ClassPathBeanDefinitionScanner来完成类路径下的bean定义的扫描。
AbstractRefreshableApplicationContext
AbstractRefreshableApplicationContext继承自AbstractApplicationContext,支持多次进行刷新(多次调用refresh方法),每次刷新时在内部创建一个新的bean工厂的实例。子类仅仅需要实现loadBeanDefinitions方法,该方法在每次刷新时都会调用。
AbstractRefreshableConfigApplicationContext
AbstractRefreshableConfigApplicationContext继承自AbstractRefreshableApplicationContext,添加了对指定的配置文件路径的公共的处理,可以把他看作基于XML的应用上下文的基类。实现了如下的两个接口:
- BeanNameAware用于设置上下文的bean的名称,只有一个方法:void setBeanName(String name)
- InitializingBean用于上下文一切就绪后,如果还未刷新,那么就执行刷新操作,只有一个方法:void afterPropertiesSet()
AbstractXmlApplicationContext
AbstractXmlApplicationContext继承自AbstractRefreshableConfigApplicationContext,用于描绘包含能被XmlBeanDefinitionReader所理解的bean定义的XML文档。子类只需要实现getConfigResources和getConfigLocations来提供配置文件资源。
FileSystemXmlApplicationContext
FileSystemXmlApplicationContext继承自AbstractXmlApplicationContext,用于解析文件系统中XML配置文件。文件的路径可以是具体的文件路径,例如:xxx/application.xml,也可以是ant风格的配置,例如:xxx/*-context.xml。
看下面的通过文件路径来获取资源的代码:
@Override protected Resource getResourceByPath(String path) { if (path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); }
文件路径前面的/会被去掉,无论是否路径前面是否加上/,文件路径都会解析成相对路径,即基于JVM的当前工作路径。获取到的资源对象是FileSystemResource,用于处理文件系统相关的资源。
ClassPathXmlApplicationContext
ClassPathXmlApplicationContext继承自AbstractXmlApplicationContext,和FileSystemXmlApplicationContext类似,只不过ClassPathXmlApplicationContext是用于处理类路径下的XML配置文件。文件的路径可以是具体的文件路径,例如:xxx/application.xml,也可以是ant风格的配置,例如:xxx/*-context.xml。
WebApplicationContext
该接口提供了在web应用中的配置,接口提供了一个ServletContext getServletContext()用来获取ServletContext对象。该接口会和ServletContext的一个属性进行绑定,这个属性就是ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。定义了三个作用域的名称:SCOPE_REQUEST,SCOPE_SESSION,SCOPE_APPLICATION。在工厂中的bean的名称:SERVLET_CONTEXT_BEAN_NAME。ServletContext初始化参数名称:CONTEXT_PARAMETERS_BEAN_NAME。在工厂中ServletContext属性值环境bean的名称:CONTEXT_ATTRIBUTES_BEAN_NAME。
ConfigurableWebApplicationContext
ConfigurableWebApplicationContext继承自WebApplicationContext和ConfigurableApplicationContext,提供了web应用上下文的可配置的能力。相关接口定义如下:
// 设置web应用上下文的ServletContext void setServletContext(@Nullable ServletContext servletContext); // 设置web应用上下文的ServletConfig void setServletConfig(@Nullable ServletConfig servletConfig); // 获取web应用上下文的ServletConfig ServletConfig getServletConfig(); // 设置web应用上下文的命名空间 void setNamespace(@Nullable String namespace); // 获取web应用上下文的命名空间 String getNamespace(); // 以初始化参数的形式设置web应用上下文的配置文件位置 void setConfigLocation(String configLocation); // 设置web应用上下文的配置文件的位置 void setConfigLocations(String... configLocations); // 获取web应用上下文的配置文件位置 String[] getConfigLocations();
上面的接口主要都是一些设置或者获取的方法,在web应用上下文中需要用到的一些东西。
GenericWebApplicationContext
GenericWebApplicationContext继承自GenericApplicationContext,实现了ConfigurableWebApplicationContext和ThemeSource接口。该类设计的目的不是在web.xml中进行声明式的安装,而是编程式的安装,例如使用WebApplicationInitializers来构建内嵌的上下文。该接口在ConfigurableWebApplicationContext的内容都是一个伪实现,调用其中的大多数方法都会抛出异常。你也许注意到了,他实现了ThemeSource接口,那么他有什么用呢?字面意思是主题源,它设计的目的主要是用于消息的国际化。
StaticWebApplicationContext
StaticWebApplicationContext继承自StaticApplicationContext实现了ConfigurableWebApplicationContext和ThemeSource接口。该接口主要是用在测试的环境,不用于产品环境。
AbstractRefreshableWebApplicationContext
GenericWebApplicationContext继承自AbstractRefreshableConfigApplicationContext,实现了ConfigurableWebApplicationContext和ThemeSource接口,主要是用于web环境下。在web程序启动的时候,提供一个configLocations属性,通过ConfigurableWebApplicationContext接口来进行填充。子类化这个接口是很简单的,所有你所需要做的事情就是实现loadBeanDefinitions方法,来实现你自己的bean定义的加载逻辑。
XmlWebApplicationContext
XmlWebApplicationContext继承自AbstractRefreshableWebApplicationContext,接受能被XmlBeanDefinitionReader所理解的XML文档配置。对于根上下文,默认的配置文件路径是/WEB-INF/applicationContext.xml,对于命名空间为test-servlet的上下文,默认的配置文件路径是/WEB-INF/test-servlet.xml(就像servlet-name为test的DispatcherServlet实例)。
默认的配置文件路径处理的代码如下:
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}; } }
和其他的上下文一样,bean定义的加载也是在void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法中,使用的是XmlBeanDefinitionReader。
GroovyWebApplicationContext
GroovyWebApplicationContext继承自AbstractRefreshableWebApplicationContext,实现了GroovyObject接口,接受能被GroovyBeanDefinitionReader所理解的groovy bean定义脚本和XML文档配置。对于web环境,基本上是和GenericGroovyApplicationContext是等价的。对于根上下文,默认的配置文件路径是/WEB-INF/applicationContext.groovy,对于命名空间为test-servlet的上下文,默认的配置文件路径是/WEB-INF/test-servlet.xml(就像servlet-name为test的DispatcherServlet实例)。
默认的配置文件路径处理的代码如下:
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}; } }
和其他的上下文一样,bean定义的加载也是在void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法中,使用的是GroovyBeanDefinitionReader。
AnnotationConfigWebApplicationContext
AnnotationConfigWebApplicationContext继承自AbstractRefreshableWebApplicationContext,
接受注解的类作为输入(特殊的@Configuration注解类,一般的@Component注解类,与JSR-330兼容的javax.inject注解)。允许一个一个的注入,同样也能使用类路径扫描。对于web环境,基本上是和AnnotationConfigApplicationContext等价的。使用AnnotatedBeanDefinitionReader来对注解的bean进行处理,使用ClassPathBeanDefinitionScanner来对类路径下的bean进行扫描。
部分代码如下:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) { AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory); ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory); ... if (!this.annotatedClasses.isEmpty()) { .... reader.register(ClassUtils.toClassArray(this.annotatedClasses)); } if (!this.basePackages.isEmpty()) { .... scanner.scan(StringUtils.toStringArray(this.basePackages)); } String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { try { Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader()); if (logger.isTraceEnabled()) { logger.trace("Registering [" + configLocation + "]"); } reader.register(clazz); } catch (ClassNotFoundException ex) { .... } } } } }
本文思维导图
作者:张风闲
原文:https://www.cnblogs.com/zhangfengxian/p/11192054.html
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/31468.html