spring-core源码分析

概述


org.springframework.context.ApplicationContext接口是Spring IoC的容器,负责bean的初始化,配置和装配。ApplicationContext通过读取元数据(configuration metadata)获取该把bean注入到哪个对象。元数据可以是XML, Java注解或Java代码。
  Spring提供了几种ApplicationContext的实现。本地化项目使用的ClassPathXMLApplicationContext或FileSystemXMLApplicationContext. 然而XML是比较传统的配置方式,使用注解或代码配合少量XML作为元数据可以使配置更精简。
   在大多数应用场景,我们不需要自己去创建ApplicationContext的实例。例如在web应用中,只需要在web.xml中增加8行配置就可以了:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Figure 1. The Spring IoC container

IoC容器的作用

Configuration metadata

元数据的三种配置方式:

  • 完全XML
  • 少量XML(component-scan) + Java注解
  • Java代码(全部使用注解)

1 spring-core 包结构

<pre>
src
└─org
└─springframework
├─asm
├─cglib
│ └─core
├─core
│ ├─annotation
│ ├─codec
│ ├─convert
│ │ ├─converter
│ │ └─support
│ ├─env
│ ├─io
│ │ ├─buffer
│ │ └─support
│ ├─serializer
│ │ └─support
│ ├─style
│ ├─task
│ │ └─support
│ └─type
│ ├─classreading
│ └─filter
├─lang
├─objenesis
└─util
├─backoff
├─comparator
├─concurrent
└─xml
</pre>

1.1 spring-core各模块功能说明

1.asm Spring将ASM代码重新打包,提供ASM依赖。
http://blog.csdn.net/whos2002110/article/details/40817939
2.cglib cglib生成的动态代理类命名规则(className$$classNameBySpringCGLIB$$hashCode)
3.core
4.lang 条件编译注解
5.objenesis 对象实例化工具,封装后提供缓存功能(单例)
6.util 各种工具类

2 spring-core.core

<pre>
core
├─annotation
├─codec
├─convert
│ ├─converter
│ └─support
├─env
├─io
│ ├─buffer
│ └─support
├─serializer
│ └─support
├─style
├─task
│ └─support
└─type
├─classreading
└─filter
</pre>
2.1 annotation


注解解析器和工具类

AnnotationUtils.getAnnotationAttributes(Annotation)  
AnnotationUtils.getValue(Annotation annotation, String attributeName)  

2.2 codec

各种编码解码工具
2.3 convert


转码工具

2.4 env##

2.4.1 概述####

env包是Spring3.1开始提供的新的属性管理API,提供配置读取和环境划分能力,主要接口:PropertySource和Environment

2.4.2 PropertySource####

PropertySource.png

PropertySource:属性源,key-value属性对抽象,比如用于配置数据
PropertyResolver:属性解析器,用于解析相应key的value

2.4.2.1主要实现类#####

MapPropertySource:属性来自于一个Map
ResourcePropertySource:属性来自于一个properties文件
ServletContextPropertySource:属性来自ServletContext上下文初始化参数
CompositePropertySource:提供了组合PropertySource的功能,查找顺序就是注册顺序。

2.4.3 Environment####

environment类图.png

Environment:环境,本身是一个PropertyResolver,但是提供了Profile特性,即可以根据环境得到相应数据(即激活不同的Profile,可以得到不同的属性数据,比如用于多环境场景的配置(正式机、测试机、开发机DataSource配置))
Profile:剖面,Environment使Spring具有了剖面特性,只有激活的剖面的组件/配置才会注册到Spring容器,类似于maven中profile。这是context包中的一个注解。另外context包中还有一个叫做EnviromentAware的类,ApplicationContext是其子类,因此我们在SpringContext中可以获取所有的配置和Profile信息。

@Inject Environment environment;
environment.getProperty( AppConfig.SERVER_HOST ),
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    if (logger.isInfoEnabled()) {
        logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                "] not matching: " + getReaderContext().getResource());
    }
    return;
}

2.5 io##

2.5.1 概述####

在日常程序开发中,处理外部资源是很繁琐的事情,我们可能需要处理URL资源、File资源资源、ClassPath相关资源、服务器相关资源(JBoss AS 5.x上的VFS资源)等等很多资源。因此处理这些资源需要使用不同的接口,这就增加了我们系统的复杂性;而且处理这些资源步骤都是类似的(打开资源、读取资源、关闭资源),因此如果能抽象出一个统一的接口来对这些底层资源进行统一访问,是不是很方便,而且使我们系统更加简洁,都是对不同的底层资源使用同一个接口进行访问。
  spring提供一个Resource接口来统一这些底层资源一致的访问,而且提供了一些便利的接口,从而能提供我们的生产力。

2.5.2 Resource接口####

Spring的Resource接口代表底层外部资源,对JDK InputStream的扩展,提供了对底层外部资源的一致性访问接口。

2.5.3 主要实现类####

2.5.3.1 ByteArrayResource#####

ByteArrayResource代表byte[]数组资源,对于“getInputStream”操作将返回一个ByteArrayInputStream。ByteArrayResource可多次读取数组资源,即isOpen ()永远返回false。

2.5.3.2 InputStreamResource#####

InputStreamResource代表java.io.InputStream字节流,对于“getInputStream ”操作将直接返回该字节流,因此只能读取一次该字节流,即“isOpen”永远返回true。

2.5.3.4 FileSystemResource

FileSystemResource代表java.io.File资源,对于“getInputStream ”操作将返回底层文件的字节流,“isOpen”将永远返回false,从而表示可多次读取底层文件的字节流。

2.5.3.5 ClassPathResource

ClassPathResource代表classpath路径的资源,将使用ClassLoader进行加载资源。classpath 资源存在于类路径中的文件系统中或jar包里,且“isOpen”永远返回false,表示可多次读取资源。
ClassPathResource加载资源替代了Class类和ClassLoader类的“getResource(String name)”和“getResourceAsStream(String name)”两个加载类路径资源方法,提供一致的访问方式。
ClassPathResource提供了三个构造器:
public ClassPathResource(String path):使用默认的ClassLoader加载“path”类路径资源;
public ClassPathResource(String path, ClassLoader classLoader):使用指定的ClassLoader加载“path”类路径资源;
比如当前类路径是“cn.javass.spring.chapter4.ResourceTest”,而需要加载的资源路径是“cn/javass/spring/chapter4/test1.properties”,则将加载的资源在“cn/javass/spring/chapter4/test1.properties”;
public ClassPathResource(String path, Class<?> clazz):使用指定的类加载“path”类路径资源,将加载相对于当前类的路径的资源;

2.5.3.6 UrlResource#####

UrlResource代表URL资源,用于简化URL资源访问。“isOpen”永远返回false,表示可多次读取资源。
UrlResource一般支持如下资源访问:
http:通过标准的http协议访问web资源,如new UrlResource(“http://地址”);
ftp:通过ftp协议访问资源,如new UrlResource(“ftp://地址”);
file:通过file协议访问本地文件系统资源,如new UrlResource(“file:d:/test.txt”);

2.5.3.7 ServletContextResource#####

ServletContextResource代表web应用资源,用于简化servlet容器的ServletContext接口的getResource操作和getResourceAsStream操作;

2.5.4 ResourceLoader接口####

public interface ResourceLoader {  
       Resource getResource(String location);  
       ClassLoader getClassLoader();  
}  

getResource接口用于根据提供的location参数返回相应的Resource对象;而getClassLoader则返回加载这些Resource的ClassLoader。

Spring提供了一个适用于所有环境的DefaultResourceLoader实现,可以返回ClassPathResource、UrlResource;还提供一个用于web环境的ServletContextResourceLoader,它继承了DefaultResourceLoader的所有功能,又额外提供了获取ServletContextResource的支持。

ResourceLoader在进行加载资源时需要使用前缀来指定需要加载:“classpath:path”表示返回ClasspathResource,“http://path”和“file:path”表示返回UrlResource资源,如果不加前缀则需要根据当前上下文来决定,DefaultResourceLoader默认实现可以加载classpath资源。

2.6 serializer##

序列化和反序列化

public interface Serializer<T> {
    void serialize(T object, OutputStream outputStream) throws IOException;
}
public interface Deserializer<T> {
    T deserialize(InputStream inputStream) throws IOException;
}

2.7 style

格式化输出工具类
···
public interface ValueStyler {
String style(Object value);
}
public interface ToStringStyler {
void styleStart(StringBuilder buffer, Object obj);
void styleEnd(StringBuilder buffer, Object obj);
void styleField(StringBuilder buffer, String fieldName, Object value);
void styleValue(StringBuilder buffer, Object value);
void styleFieldSeparator(StringBuilder buffer);
}
···

2.8 task

2.8.1 概述####

Java SE 5.0引入了ThreadPoolExecutor、ScheduledThreadPoolExecutor。Spring 2.x借助ConcurrentTaskExecutor和ThreadPoolTaskExecutor能够通过IoC配置形式自定义它们暴露的各个属性。
TaskExecutor接口,是对java.util.concurrent.Executor接口的扩展。给其他组件提供线程池的抽象。
例如ApplicationEventMulticaster组件、JMS的AbstractMessageListenerContainer和对Quartz的整合都使用了TaskExecutor抽象来提供线程池。

task.png

2.8.2 配置与使用####

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <!-- 核心线程数 -->     
    <property name="corePoolSize" value="5" />
    <!-- 最大线程数 -->  
    <property name="maxPoolSize" value="50" />
    <!-- 队列最大长度 -->
    <property name="queueCapacity" value="1000" />
    <!-- 线程池维护线程所允许的空闲时间,默认为60s -->
    <property name="keepAliveSeconds" value="60" />
</bean>
@Resource(name = "taskExecutor")
private TaskExecutor taskExecutor;
taskExecutor.execute(()-> {
    ...
});

2.8.3 实现类

从类图上很明显可以看出分为同步Executor和异步Executor。同步比较简单,就是调用一下的run方法。下面主要分析异步。

  • SimpleAsyncTaskExecutor:每次调用都启动一个新线程。但是,它还是支持对并发总数设限,当超过线程并发总数限制时,阻塞新的调用,直到有位置被释放。
  • ConcurrentTaskExecutor:对Java 5 java.util.concurrent.Executor类的适配,暴露了Executor的配置参数作为bean属性,可以配置自己的Executor,可以设置任务装饰器。
  • **ThreadPoolTaskExecutor **:对java.util.concurrent.ThreadPoolExecutor的包装。
  • ThreadPoolTaskScheduler:对java.util.concurrent.ScheduledExecutorService的封装,并提供了@Scheduled 注解,极大简化了ScheduledExecutorService的操作。
    使用方法:
// 修改spring context配置文件,增加xmlns和xsi
// xmlns
xmlns:task="http://www.springframework.org/schema/task"
// xsi
http://www.springframework.org/schema/task  
http://www.springframework.org/schema/task/spring-task-3.1.xsd  
//增加task注解扫描
<task:annotation-driven/>  
// 方法上加Scheduled 注解,支持fixedDelay、Cron等多种方式
@Scheduled(cron="0/3 * *  * * ? ")   //每3秒执行一次  
public void foo(){  
    ...  
} 

3.Spring-Core.utils#

<pre>
util
├─backoff
├─comparator
├─concurrent
└─xml
</pre>

3.1 backoff##

backoff.png

Spring封装的退避算法,用于获取重试间隔。两个实现类,FixedBackOff是按照固定时间间隔重试,ExponentialBackOff是间隔以指数方式增长。

3.2 concurrent##

Spring中对java.util.concurrent.Future的扩展,支持Future适配,FutureTask添加多个回调函数。

20141119213430375.jpg

3.2.1 主要类

ListenableFuture<T>:增加扩展功能使用addCallback()方法支持增加回调函数
ListenableFutureTask<T>:FutureTask子类,主要是为了增加回调函数注册和回调函数调用功能。该类重写了done()方法,执行对回调函数队列的调用。

3.2.2 应用####

这个工具类应用在Spring4.1的异步新特性中。Spring4.1提供了@Asyc注解,被注解的类或方法将拥有异步处理能力

  • 相关的配置:
    <task:annotation-driven />指定@Async使用的线程池
    <task:executor />配置线程池参数

3.3 各种工具类##

ClassUtils:Class类工具,提供操作class类的方法。
比如:获知类、方法上是否有注解,获取类注解,获取某package下所有class等。提供class缓存
CollectionUtils:集合工具类,提供集合的转换、查找、判空等方法。
DigestUtils:对java.serurity.MessageDigest的封装,提供单向加密方法。
ReflectionUtils:反射工具类,提供各种反射操作,并包装了反射过程中可能出现的异常。
SystemPropertyUtils:placeholder解析工具类。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,739评论 6 342
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,463评论 25 707
  • 出走的猫咪 流浪的狗 幸福是自由 在霓虹路口 要不要留,该不该走 我站在你家门口 恋人的眼神,醉人的酒 喜悦是眼泪...
    俞米阅读 272评论 0 5
  • 每天明白一个道理,每天习得一句英文! 温柔暴击立德金句,等你一起读~ 2017.11.15立德金句中英文: The...
    瞳小甜Rosie阅读 202评论 0 0