Spring随笔之ApplicationContext

前言

以前自己学习和实习的时候多次用过spring框架。对于我这种菜鸟来说,Spring给我的第一印象是好学,太TM好学了(抱歉没忍住脏话),跟着开发组熟悉几天就可以开始写代码,自我感觉代码敲得飞起~(苦笑),随着学习的深入,才发现自己坐井观天,还有太多的东西要学。现在决定沉下心来好好的找找自己的短板,本系列文章不会系统的介绍Spring的知识。首先明确定位,本系列的博客是小白文,我也是个学习者,可能很多东西大家看了会觉so easy,但适合自己的对我来说就是最好的,也记录成长的一个过程。

说明,如果文章借鉴一些前辈们的辛苦成果,会在文章最后标明。如有侵权问题或者不满意的地方请留言,我会第一时间修改。

 

1 ApplicationContext

API介绍如下:

public interface ApplicationContext
extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver

Central interface to provide configuration for an application. This is read-only while the application is running, but may be reloaded if the implementation supports this.

An ApplicationContext provides:

    Bean factory methods for accessing application components. Inherited from ListableBeanFactory.
    The ability to load file resources in a generic fashion. Inherited from the ResourceLoader interface.
    The ability to publish events to registered listeners. Inherited from the ApplicationEventPublisher interface.
    The ability to resolve messages, supporting internationalization. Inherited from the MessageSource interface.
    Inheritance from a parent context. Definitions in a descendant context will always take priority. This means, for example, that a single parent context can be used by an entire web application, while each servlet has its own child context that is independent of that of any other servlet.

In addition to standard BeanFactory lifecycle capabilities, ApplicationContext implementations detect and invoke ApplicationContextAware beans as well as ResourceLoaderAware, ApplicationEventPublisherAware and MessageSourceAware beans.

很好理解,ApplicationContext很重要,它为应用提供配置,当应用运行时他是可读的,但是可以被重新加载。

 

ApplicationContext接口继承了EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver等接口,这些接口让ApplicationContext具有如下功能:

(1)提供访问应用组件的bean工厂方法,该功能继承自ListableBeanFactory接口。

(2)提供通用的方式加载文件资源,该功能继承自ResourceLoader接口。

(3)将事件发布给注册的监听器。该功能继承自ApplicationEventPublisher接口。

(4)解决消息和支持国际化,该功能继承自MessageSource接口。

(5)从父上下文继承。子上下文中的定义总是优先考虑。例如,整个web应用有一个父上下文,而每个servlet都有自己独立的子上下文。

除了标准BeanFactory的能力,ApplicationContext还实现检测和调用ApplicationContextAware ResourceLoaderAware、ApplicationEventPublisherAware and MessageSourceAware。

 

上述就是简单的将官方API翻译了一遍~~ 仔细的读者可能脑海中,冒出了至少有两个问题。

问题1:上述功能第2条说ApplicationContext加载文件资源的功能继承自ResourceLoader,而该ApplicationContext接口在声明是并没有没有继承该接口,那么是怎么继承的?

答:仔细看ApplicationContext接口的声明,发现它继承了ResourcePatternResolver。跟进源码发现ResourcePatternResolver继承了ResourceLoader。所以说ResourceLoaderApplicationContext是爷孙关系,并不是父子关系。

那么问题又来了,框架设计者为什么要这么“多此一举”?

源码中的类注释是这样写的:

Strategy interface for resolving a location pattern (for example,an Ant-style path pattern) into Resource objects.

这是一个策略接口,这样做的目的是为了将一个 location模式解析到一个资源对象中,例如Ant风格的路径模式。(这里好像还是不理解,原谅我的菜~,不如先看看ResourceLoader接口回头再来理解。

ResourceLoader接口源码:

 1 /**
 2  * Strategy interface for loading resources (e.. class path or file system
 3  * resources). An {@link org.springframework.context.ApplicationContext}
 4  * is required to provide this functionality, plus extended
 5  * {@link org.springframework.core.io.support.ResourcePatternResolver} support.
 6  *
 7  * <p>{@link DefaultResourceLoader} is a standalone implementation that is
 8  * usable outside an ApplicationContext, also used by {@link ResourceEditor}.
 9  *
10  * <p>Bean properties of type Resource and Resource array can be populated
11  * from Strings when running in an ApplicationContext, using the particular
12  * context's resource loading strategy.
13  *
14  * @author Juergen Hoeller
15  * @since 10.03.2004
16  * @see Resource
17  * @see org.springframework.core.io.support.ResourcePatternResolver
18  * @see org.springframework.context.ApplicationContext
19  * @see org.springframework.context.ResourceLoaderAware
20  */
21 public interface ResourceLoader {
22 
23     /** Pseudo URL prefix for loading from the class path: "classpath:" */
24     String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
25 
26 
27     /**
28      * Return a Resource handle for the specified resource location.
29      * <p>The handle should always be a reusable resource descriptor,
30      * allowing for multiple {@link Resource#getInputStream()} calls.
31      * <p><ul>
32      * <li>Must support fully qualified URLs, e.g. "file:C:/test.dat".
33      * <li>Must support classpath pseudo-URLs, e.g. "classpath:test.dat".
34      * <li>Should support relative file paths, e.g. "WEB-INF/test.dat".
35      * (This will be implementation-specific, typically provided by an
36      * ApplicationContext implementation.)
37      * </ul>
38      * <p>Note that a Resource handle does not imply an existing resource;
39      * you need to invoke {@link Resource#exists} to check for existence.
40      * @param location the resource location
41      * @return a corresponding Resource handle (never {@code null})
42      * @see #CLASSPATH_URL_PREFIX
43      * @see Resource#exists()
44      * @see Resource#getInputStream()
45      */
46     Resource getResource(String location);
47 
48     /**
49      * Expose the ClassLoader used by this ResourceLoader.
50      * <p>Clients which need to access the ClassLoader directly can do so
51      * in a uniform manner with the ResourceLoader, rather than relying
52      * on the thread context ClassLoader.
53      * @return the ClassLoader
54      * @see org.springframework.util.ClassUtils#getDefaultClassLoader()
55      */
56     @Nullable
57     ClassLoader getClassLoader();
58 
59 }

 

一个静态常量CLASSPATH_URL_PREFIX = "classpath:"

两个成员方法getResourcegetClassLoader

多余的这里我就不翻译了,相信大部分同学的英语水准都比四级都差点没过的我要强。

仔细看getResource(String location)返回值是Resource ,这又是个什么鬼?继续点进去看源码发现其声明如下:

public interface Resource extends InputStreamSource

基本上可以猜到封装了一个输入流,加一些包装的方法等。如果InputStream的原理不懂的,可以看一下java的InputStream源码。

尼玛~本章的内容我没记错的话好像是ApplicationContext,似乎是有点跑偏了,接下来回到问题1抛出的新问题(还是有点偏,大家先忍忍)。

为什需要一个ResourcePatternResolver,我们看看该接口的源码:

 

 1 public interface ResourcePatternResolver extends ResourceLoader {
 2 
 3     /**
 4      * Pseudo URL prefix for all matching resources from the class path: "classpath*:"
 5      * This differs from ResourceLoader's classpath URL prefix in that it
 6      * retrieves all matching resources for a given name (e.g. "/beans.xml"),
 7      * for example in the root of all deployed JAR files.
 8      * @see org.springframework.core.io.ResourceLoader#CLASSPATH_URL_PREFIX
 9      */
10     String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
11 
12     /**
13      * Resolve the given location pattern into Resource objects.
14      * <p>Overlapping resource entries that point to the same physical
15      * resource should be avoided, as far as possible. The result should
16      * have set semantics.
17      * @param locationPattern the location pattern to resolve
18      * @return the corresponding Resource objects
19      * @throws IOException in case of I/O errors
20      */
21     Resource[] getResources(String locationPattern) throws IOException;
22 
23 }

 

里面有一个常量CLASSPATH_ALL_URL_PREFIX = "classpath*:"

回顾父接口常量CLASSPATH_URL_PREFIX = "classpath:"

发生了什么?多了一个“*”号!可能到这里很多读者已经想起来Ant-style path pattern的三个符号了

? 匹配任何单字符  
* 匹配0或者任意数量的字符  
** 匹配0或者更多的目录

getResources方法的返回值是个数组,到此恍然大悟,一个模式可能匹配多个文件。到此问题1算是解决了~

 

问题2:官方文档似乎没有介绍继承EnvironmentCapable, HierarchicalBeanFactory两个接口有什么用?

我们先看EnvironmentCapable源码:

1 public interface EnvironmentCapable {
2 
3     /**
4      * Return the {@link Environment} associated with this component.
5      */
6     Environment getEnvironment();
7 
8 }

该接口表面上的作用是提供一个Environment的引用,这有什么用?

源码的类注释解释了,大概意思是:spring中所有context都继承了该接口,这样做的目的是用于类型检查,例如框架中有些与用户定义的BeanFactory交互的方法,这些方法有些就需要使用用户定义的BeanFactory的环境变量。这个时候就要看其是否是EnvironmentCapable接口的子类了。

注释还强调了ConfigurableApplicationContext重写了getEnvironment,其返回值是ConfigurableEnvironment。

ConfigurableApplicationContext又是哪来的,后面进入本章高潮了再介绍。

再看HierarchicalBeanFactory源码:

 

 1 public interface HierarchicalBeanFactory extends BeanFactory {
 2 
 3     /**
 4      * Return the parent bean factory, or {@code null} if there is none.
 5      */
 6     @Nullable
 7     BeanFactory getParentBeanFactory();
 8 
 9     /**
10      * Return whether the local bean factory contains a bean of the given name,
11      * ignoring beans defined in ancestor contexts.
12      * <p>This is an alternative to {@code containsBean}, ignoring a bean
13      * of the given name from an ancestor bean factory.
14      * @param name the name of the bean to query
15      * @return whether a bean with the given name is defined in the local factory
16      * @see BeanFactory#containsBean
17      */
18     boolean containsLocalBean(String name);
19 
20 }

 

HierarchicalBeanFactory也继承了BeanFactory,为什么是也?还记得ApplicationContext的功能1吗?因为ListableBeanFactory肯定继承了BeanFactory(不要问我为什么知道)

 

HierarchicalBeanFactory有两个方法:(1)得到父bean factory.(2)返回本地bean工厂是否包含给定名称的bean,忽略在祖先上下文中定义的bean。

留个思考题:为什么要这么设计?为什么??

到此,ApplicationContext继承的多个接口我们都知道其作用了,有几个API中解释了的接口还没深入源码,感兴趣的可以继续~~~

 

ApplicationContext继承了那么多功能,那么它自己有什么独特的呢?

 

其他方法都好理解,这里似乎有1个问题:这里为什么要暴露出AutowireCapableBeanFactory?搞明白该接口的作用解决该问题的希望可能会更大(这不废话么,哈哈)。

 

TODO:AutowireCapableBeanFactory

 

下面介绍ApplicationContext的层级关系

太多了,部分没展开。大家是否发现了自己熟悉的context,例如ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext等。

类图懒得画了,找了一个,如下(来自:http://blog.csdn.net/h12kjgj/article/details/53725507)

 

TODO:解读常用的context源码

 

 下文是本文梳理的重点(来自:http://blog.csdn.net/h12kjgj/article/details/53725507)

 

转载于:https://www.cnblogs.com/ouym/p/8506849.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值