spring 详解笔记

各变量说明

对象名 类 型 作 用 归属类
aliasMap Map<String, String> 存储Bean名称->Bean别名映射关系 SimpleAliasRegistry
singletonObjects Map<String, Object> 存储单例Bean名称->单例Bean实现映射关系 DefaultSingletonBeanRegistry
singletonFactories Map<String, ObjectFactory> 存储Bean名称->ObjectFactory实现映射关系 DefaultSingletonBeanRegistry
earlySingletonObjects Map<String, Object> 存储Bean名称->预加载Bean实现映射关系 DefaultSingletonBeanRegistry
registeredSingletons Set 存储注册过的Bean名 DefaultSingletonBeanRegistry
singletonsCurrentlyInCreation Set 存储当前正在创建的Bean名 DefaultSingletonBeanRegistry
disposableBeans Map<String, Object> 存储Bean名称->Disposable接口实现Bean实现映射关系 DefaultSingletonBeanRegistry
factoryBeanObjectCache Map<String, Object> 存储Bean名称->FactoryBean接口Bean实现映射关系 FactoryBeanRegistrySupport
propertyEditorRegistrars Set 存储PropertyEditorRegistrar接口实现集合 AbstractBeanFactory
embeddedValueResolvers List 存储StringValueResolver(字符串解析器)接口实现列表 AbstractBeanFactory
beanPostProcessors List 存储 BeanPostProcessor接口实现列表 AbstractBeanFactory
mergedBeanDefinitions Map<String, RootBeanDefinition> 存储Bean名称->合并过的根Bean定义映射关系 AbstractBeanFactory
alreadyCreated Set 存储至少被创建过一次的Bean名集合 AbstractBeanFactory
ignoredDependencyInterfaces Set 存储不自动装配的接口Class对象集合 AbstractAutowireCapableBeanFactory
resolvableDependencies Map<Class, Object> 存储修正过的依赖映射关系 DefaultListableBeanFactory
beanDefinitionMap Map<String, BeanDefinition> 存储Bean名称–>Bean定义映射关系 DefaultListableBeanFactory
beanDefinitionNames List 存储Bean定义名称列表 DefaultListableBeanFactory

Ioc

BeanFactory&&Application

  • BeanFactory实现了容器的最基本功能getBean

  • AutowireCapableBeanFactory实现自动装配能力,为bean注入属性autowireBeanProperties,bean的实例化initializeBean,各类装配autowire

  • HierarchicalBeanFactory继承了BeanFactory的基本接口之后

    • 增加了getParentBeanFactory()的接口功能,使BeanFactory具备双亲IOC容器的管理功能
  • ConfigurableBeanFactory接口中定义了一些对BeanFactory的配置功能

    • setParentBeanFactory()设置双亲IOC容器
    • addBeanPostProcessor()配置Bean后置处理器
  • ListableBeanFactory细化了很多BeanFactory的接口功能

    • getBeanDefinitionNames()接口方法
  • ApplicationContext基于HierarchicalBeanFactory&ListableBeanFactory而实现的并增加了

    • MessageSource国际化处理
    • ResourceLoader资源定位
    • ApplicationEventPublisher应用事件推送

AbstractApplicationContext

整个Spring的声明周期类

函数名 功能
prepareRefresh 容器预先准备,记录容器启动时间和标记
obtainFreshBeanFactory 创建Bean工厂,有则销毁无则创建,实现了beanDefinition装载
prepareBeanFactory 配置bean工厂标准上下文,如类装载器,PostProcesser等
postProcessorBeanFactory 模板方法,提供后期准备
invokeBeanFactoryPostProcessor 传进来的是beanFactory,可以这个bean去获得各个beanDefinition并修改
registerBeanPostProcessors 注册BeanPostProcessor
initMessageSource 初始化MessageResource
initApplicationEventMulticaster 初始化上下文事件广播
onRefresh 最重要的方法,AnnotationConfigEmbeddedWebApplication是用来创建Servlet容器
registerListeners 注册监听器,实现ApplicationListener的监听器
finishBeanFactoryInitialization preInstantiateSingletons让单例提前实例化
finishRefresh LifecycleProcessor().onRefresh() 实现LifecycleProcessor的进行refresh并且发出event
  • obtainFreshBeanFactory --> refreshBeanFactory负责BeanDefinition资源的定位、读入和注册过程
  • prepareBeanFactory
    • ignoreDependencyInterface:设置了几个忽略自动装配的接口,主要功能是Bean如果是这些接口的实现类,则不会被自动装配,ApplicationContextAwareProcessor
    • registerResolvableDependency:设置了几个忽略自动装配的接口,意思是修正依赖,这里是一些自动装配的特殊规则,比如是BeanFactory接口的实现类,则修正为当前BeanFactory

refresh()方法解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 为刷新准备上下文,获取容器的startupDate时间,同时给容器设置closed=false/active=true标识
prepareRefresh();

// 获得内部bean工厂 --> obtainFreshBeanFactory --> refreshBeanFactory
//refreshBeanFactory:委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
//DefaultListableBeanFactory beanFactory = createBeanFactory(); 创建IoC容器
//并且把当前的beanFactory通过getBeanFactory返回
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();


//给beanFactory注册一些标准组建,如ClassLoader,StandardEnvironment,BeanProcess
prepareBeanFactory(beanFactory);

try {
//为容器的某些子类指定特殊的postProcessor事件处理器,当前类暂未写代码实现
postProcessBeanFactory(beanFactory);

// 调用所有注册的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);

// 注册用于拦截bean创建的bean处理器
registerBeanPostProcessors(beanFactory);

// 为上下文初始化信息源,和国际化相关.
initMessageSource();

// 初始化上下文中的事件多路广播机制
initApplicationEventMulticaster();

// 初始化指定context子类中的特殊bean
onRefresh();

// 注册并检查bean监听器
registerListeners();

// 初始化剩下的非延迟加载(non-lazy-init)单例beans
finishBeanFactoryInitialization(beanFactory);

// 最后一步,发布相关的容器事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例bean
destroyBeans();
// 取消refresh操作,充值'activity'标志位
cancelRefresh(ex);

throw ex;
}
finally {
resetCommonCaches();
}
}
}

AbstractBeanFactory

有关循环依赖A中有依赖B,B中有依赖A的Spring解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
三级缓存分别指: 
singletonFactories : 单例对象工厂的cache
earlySingletonObjects :提前暴光的单例对象的Cache
singletonObjects:单例对象的cache


protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}

A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。

doGetBean

  • 1:转移对应beanName

    1
    这里传入的可能是aliasName(别名),也可能是FactoryBean,所以要进步一解析
  • 2:尝试从缓存中加载单例

    1
    2
    3
    4
    单例在spring的同一个容器内只会被创建一次,后续在获取bean,直接从缓存拿
    如果加载不成功,则再次从singletonFactory中加载,因为在创建单例bean的时候会存在依赖注入的情况,为了避免循环依赖
    spring中创建bean的原则是不等bean创建完成就创建bean的ObjectFactory提早曝光加入缓存中
    一旦下一个bean创建的时候需要依赖上一个bean则直接使用objectFactory
  • 3:bean的实例化

    1
    2
    3
    4
    5
    如果从缓存中得到bean的原始状态,则需要对bean进行实例化
    缓存中有原始的bean状态,并不是我们最终想要的bean
    比如我们工程bean进行处理,那么这里得到的其实是工厂bean的初始状态
    但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean
    而getObjectForBeanInstance就是做这个工作
  • 4:原型模式的依赖检查

    1
    2
    只有在单例模式才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性
    name当依赖注入的时候就会产生A还未创建完的时候因为B的创建再次返回创建A,造成循环依赖
  • 5:检查parentBeanFactory

    1
    2
    3
    if (parentBeanFactory != null && !containsBeanDefinition(beanName))
    这里面!containsBeanDefinition(beanName)检查当前的xml配置文件不包含beanName
    所对应的配置,就只能parentBeanFactory去尝试下了,然后再去递归的调用getBean方法
  • 6:将存储xml配置文件的GernericBeanDefinition转换为RootBeanDefinition

    1
    2
    因为xml配置文件读取到的bean信息是存储在GernericBeanDefinition中的
    但是所有的bean后续处理都是针对RootBeanDefinition的,所以要转换,同时如果父类的bean不为空则会一并合并父类属性
  • 7:寻找必先依赖

    1
    2
    3
    4
    5
    因为bean的配置必须依赖于其他bean先实例化,那么这个时候就有必要先加载依赖的bean
    所以在加载顺序中, 会初始化某一个bean的时候先初始化这个bean所应对的依赖

    <bean id="goods" class="org.ifly.edu.spring.bean.dependOn.Goods" depends-on="user"/>
    goods实例化前先实例化user
  • 8:针对不同的scope进行bean的实例化

    1
    默认是singleton,还有prototype,request之类的,会根据不同配置进行不同初始化策略
  • 9:类型转换

    1
    2
    3
    程序到这里返回bean基本结束了,通常对该方法的的调用参数requiredType是为空的
    但是如果返回的bean其实是个string,但是requiredType却传入Integer类型
    那么这个时候就会将bean转换成requiredType所指定的类型了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
 protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {

//提取对应的beanName
final String beanName = transformedBeanName(name);
Object bean;

/**
检查缓存中或者实例工厂中是否有对应的实例
为什么首先会使用这段代码呢
因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
Spring创建bean的原则不是等bean创建完成就会创建bean的objectFactory提早曝光
也就是将objectFactory加入到缓存中,一旦下个bean创建时候需要依赖上个bean则直接使用objectFactory
*/
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//返回对应实例,有时候存在诸如BeanFactory的情况
//不是直接返回实例本身而是返回指定方法返回的实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在
//A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还没创建完的时候因为
//对于B的创建再次返回创建A,造成循环依赖,也就是下面的情况
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}


BeanFactory parentBeanFactory = getParentBeanFactory();

//如果beanDefinitionMap中也就是在所有已经加载的类不包括beanName则尝试从parentBeanFactory
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);

//递归到BeanFactory中寻找
if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}

//如果不是仅仅做类型检查则创建Bean,这里进行记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}

try {
//将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition
//如果指定BeanName是子Bean的话同时会合并到父类的相关属性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

String[] dependsOn = mbd.getDependsOn();
//如果存在依赖则需要递归实例化依赖的bean
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
if (isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
}
registerDependentBean(dependsOnBean, beanName);
getBean(dependsOnBean);
}
}

//实例化依赖的bean后便可以实例化mbd了
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {

destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
//prototype模式的创建
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

else {
//指定的scope上实例化bean
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}

//检查需要的类型是否符合bean的实际类型
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}

createBean

1
2
3
4
5
6
7
8
9
10
11
12
13
先实例化createBeanInstance  
后检测是否需要earlySingletonExposure,需要则加入addSingletonFactory
再进行设置对象属性populateBean(后期对BeanWrapper进行applyPropertyValues)
接下来进入initializeBean

initializeBean主要进行四步骤
- invokeAwareMethods(BeanNameAware,BeanClassLoaderAware,BeanFactoryAware进行各种资源set)
- BeanPostProcessor#postProcessBeforeInitialization
- InitializingBean#afterPropertiesSet(如果当前的bean实现此接口就执行)
- invokeInitMethods#invokeCustomInitMethod(如果有自定义init-method,则进行init-method实例化)
- BeanPostProcessor#postProcessAfterInitialization

至此结束
  • createBeanInstance: 创建bean的时候将会选取实例化策略SimpleInstantiationStrategy,CglibSubclassingInstantiationStrategy
    • 通过BeanUtils,利用JVM的反射功能
    • 利用CGLIB去生成代理
      • 如果有使用到lookup-methodreplace-method,进入到instantiateBean方法可以看到如果有方法覆盖(MethodOverride)将调用cglib的instantiateWithMethodInjection

BeanDefinitionReader

XmlBeanDefinitionReader

1
2
3
4
5
6
7
AbstractWebApplicationContext#invokeBeanFactoryPostProcessors  --->  PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
//invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
//调用BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
ConfigurationClassPostProcessor#processConfigBeanDefinitions
//this.reader.loadBeanDefinitions(configClasses);

由此引入XmlBeanDefinitionReader

AnnotatedBeanDefinitionReader

1
SpringApplication#prepareContext ---> SpringApplication#load

生命周期

img

扩展

InitialingBean

InitialingBean是一个接口,提供了一个唯一的方法afterPropertiesSet()。

在Bean属性都设置完毕后调用afterPropertiesSet()方法做一些初始化的工作

1
afterPropertiesSet方法在set属性之后执行

DisposableBean

DisposableBean也是一个接口,提供了一个唯一的方法destory()。

在Bean生命周期结束前调用destory()方法做一些收尾工作

InitializingBean接口、Disposable接口底层进行直接方法调用
init-method、destory-method底层使用反射
前者和Spring耦合程度更高但效率高
后者解除了和Spring之间的耦合但是效率低

BeanNameAware

实现BeanNameAware接口的Bean,在Bean加载的过程中可以获取到该Bean的id

1
2
3
4
5
public void setBeanName(String beanName)
{
System.out.println("Enter AwareBean.setBeanName(), beanName = " + beanName + "\n");
this.beanName = beanName;
}

ApplicationContextAware

Bean加载的过程中可以获取到Spring的ApplicationContext

从ApplicationContext中可以获取包括任意的Bean在内的大量Spring容器内容和信息

1
2
3
4
5
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
System.out.println("Enter AwareBean.setApplicationContext(), applicationContext = " + applicationContext + "\n");
this.applicationContext = applicationContext;
}

BeanFactoryAware

Bean加载的过程中可以获取到加载该Bean的BeanFactory

1
2
3
4
5
public void setBeanFactory(BeanFactory beanFactory) throws BeansException
{
System.out.println("Enter AwareBean.setBeanFactory(), beanfactory = " + beanFactory + "\n");
this.beanFactory = beanFactory;
}

FactoryBean

FactoryBean,开发者可以个性化地定制自己想要实例化出来的Bean,方法就是实现FactoryBean接口。

  1. getObject()方法是最重要的,控制Bean的实例化过程
  2. getObjectType()方法获取接口返回的实例的class
  3. isSingleton()方法获取该Bean是否为一个单例的Bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class AnimalFactoryBean implements FactoryBean<Animal>
{
private String animal;

public Animal getObject() throws Exception{
if ("Monkey".equals(animal))
{
return new Monkey();
}
else if ("Tiger".equals(animal))
{
return new Tiger();
}
else
{
return null;
}
}
public Class<?> getObjectType(){
return Animal.class;
}
public boolean isSingleton(){
return true;
}
public void setAnimal(String animal){
this.animal = animal;
}
}

BeanPostProcess

  • postProcessBeforeInitialization:在初始化Bean之前

  • postProcessAfterInitialization:在初始化Bean之后

不要返回null,否则getBean的时候拿不到对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class PostProcessorBean implements BeanPostProcessor
{
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
System.out.println("Enter ProcessorBean.postProcessAfterInitialization()\n");
return bean;
}

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
System.out.println("Enter ProcessorBean.postProcessBeforeInitialization()");
return bean;
}
}

BeanFactoryPostProcessor

PostProcessor之后的BeanFactoryPostProcessor

  1. BeanFactoryPostProcessor的执行优先级高于BeanPostProcessor

  2. BeanFactoryPostProcessor的postProcessBeanFactory()方法只会执行一次

InstantiationAwareBeanPostProcessor

  • 实例化:实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中
  • 初始化:初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性

BeanDefinitionRegistryPostProcessor

这个接口继承了BeanFactoryPostProcessor. 从名字上来看, 这个接口是BeanDefinitionRegistry的后处理器

我们先介绍下BeanDefinitionRegistry.
BeanDefinitionRegistry是用来注册BeanDefinition的. BeanDefinition就是Bean的配置元数据或Bean的描述信息, 比如Bean的属性值, 构造方法的参数值等. 上面的BeanFactory的BeanDefinition也是由它注册的.

BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的扩展, 允许在BeanFactoryPostProcessor被调用之前对BeanDefinition做一些操作, 尤其是它可以注册BeanFactoryPostProcessor的BeanDefinition. 它提供了一个方法postProcessBeanDefinitionRegistry(), 这个方法被调用的时候, 所有的BeanDefinition已经被加载了, 但是所有的Bean还没被创建.

注意:

所有的Bean生成都有个顺序: 定义 –> 创建 –> 初始化.
BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法在Bean被定义但还没被创建的时候执行.
BeanFactoryPostProcessor的postProcessBeanFactory方法在Bean被创建但还没被初始化的时候执行

案例

Mybatis的MapperScannerConfigurer

ImportBeanDefinitionRegistrar

动态注册bean
Spring官方在动态注册bean时,大部分套路其实是使用ImportBeanDefinitionRegistrar接口。

所有实现了该接口的类的都会被ConfigurationClassPostProcessor处理,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口
所以ImportBeanDefinitionRegistrar中动态注册的bean是优先与依赖其的bean初始化的,也能被aop、validator等机制处理。

案例

Apollo阿波罗配置框架ApolloConfigRegistrar
Mybatis的@MapperScan中Import了ImportBeanDefinitionRegistrar






工具类

内置的resouce类型

1
2
3
4
5
6
7
8
UrlResource
ClassPathResource
FileSystemResource
ServletContextResource
InputStreamResource
ByteArrayResource
EncodedResource //也就是Resource加上encoding, 可以认为是有编码的资源 VfsResource(在jboss里经常用到, 相应还有 工具类 VfsUtils)
org.springframework.util.xml.ResourceUtils //用于处理表达资源字符串前缀描述资源的工具有 getURL, getFile, isFileURL, isJarURL, extractJarFileURL

常用工具

1
2
3
4
5
6
org.springframework.core.annotation.AnnotationUtils   处理注解
org.springframework.core.io.support.PathMatchingResourcePatternResolver 用 于处理 ant 匹配风格(com/*.jsp, com/**/*.jsp),找出所有的资源, 结合上面的resource的概念一起使用,对于遍历文件很有用. 具体请详细查看javadoc
org.springframework.core.io.support.PropertiesLoaderUtils 加载Properties资源工具类,和Resource结合
org.springframework.core.BridgeMethodResolver 桥接方法分析器. 关于桥接方法请参考: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.4.5
org.springframework.core.GenericTypeResolver 范型分析器, 在用于对范型方法, 参数分析.
org.springframework.core.NestedExceptionUtils

xml工具

org.springframework.util.xml.AbstractStaxContentHandler
org.springframework.util.xml.AbstractStaxXMLReader
org.springframework.util.xml.AbstractXMLReader
org.springframework.util.xml.AbstractXMLStreamReader
org.springframework.util.xml.DomUtils
org.springframework.util.xml.SimpleNamespaceContext
org.springframework.util.xml.SimpleSaxErrorHandler
org.springframework.util.xml.SimpleTransformErrorListener
org.springframework.util.xml.StaxUtils
org.springframework.util.xml.TransformerUtils

其它工具集

org.springframework.util.xml.AntPathMatcher ant风格的处理
org.springframework.util.xml.AntPathStringMatcher
org.springframework.util.xml.Assert 断言,在我们的参数判断时应该经常用
org.springframework.util.xml.CachingMapDecorator
org.springframework.util.xml.ClassUtils 用于Class的处理
org.springframework.util.xml.CollectionUtils 用于处理集合的工具
org.springframework.util.xml.CommonsLogWriter
org.springframework.util.xml.CompositeIterator
org.springframework.util.xml.ConcurrencyThrottleSupport
org.springframework.util.xml.CustomizableThreadCreator
org.springframework.util.xml.DefaultPropertiesPersister
org.springframework.util.xml.DigestUtils 摘要处理, 这里有用于md5处理信息的
org.springframework.util.xml.FileCopyUtils 文件的拷贝处理, 结合Resource的概念一起来处理, 真的是很方便
org.springframework.util.xml.FileSystemUtils
org.springframework.util.xml.LinkedCaseInsensitiveMap key值不区分大小写的LinkedMap
org.springframework.util.xml.LinkedMultiValueMap 一个key可以存放多个值的LinkedMap
org.springframework.util.xml.Log4jConfigurer 一个log4j的启动加载指定配制文件的工具类
org.springframework.util.xml.NumberUtils 处理数字的工具类, 有parseNumber 可以把字符串处理成我们指定的数字格式, 还支持format格式, convertNumberToTargetClass 可以实现Number类型的转化.
org.springframework.util.xml.ObjectUtils 有很多处理null object的方法. 如nullSafeHashCode, nullSafeEquals, isArray, containsElement, addObjectToArray, 等有用的方法
org.springframework.util.xml.PatternMatchUtils spring里用于处理简单的匹配.
org.springframework.util.xml.PropertyPlaceholderHelper 用于处理占位符的替换
org.springframework.util.xml.ReflectionUtils 反映常用工具方法. 有 findField, setField, getField, findMethod, invokeMethod等有用的方法
org.springframework.util.xml.SerializationUtils 用于java的序列化与反序列化. serialize与deserialize方法
org.springframework.util.xml.StopWatch 一个很好的用于记录执行时间的工具类, 且可以用于任务分阶段的测试时间. 最后支持一个很好看的打印格式. 这个类应该经常用
org.springframework.util.xml.StringUtils
org.springframework.util.xml.SystemPropertyUtils
org.springframework.util.xml.TypeUtils 用于类型相容的判断. isAssignable
org.springframework.util.xml.WeakReferenceMonitor 弱引用的监控

web相关

org.springframework.web.util.CookieGenerator
org.springframework.web.util.HtmlCharacterEntityDecoder
org.springframework.web.util.HtmlCharacterEntityReferences
org.springframework.web.util.HtmlUtils
org.springframework.web.util.HttpUrlTemplate //这个类用于用字符串模板构建url, 它会自动处理url里的汉字及其它相关的编码. 在读取别人提供的url资源时, 应该经常用
org.springframework.web.util.JavaScriptUtils
org.springframework.web.util.Log4jConfigListener //用listener的方式来配制log4j在web环境下的初始化
org.springframework.web.util.UriTemplate
org.springframework.web.util.UriUtils 处理uri里特殊字符的编码
org.springframework.web.util.WebUtils

Aop

一个正常的提前实例化单例实例

1
2
3
4
5
sequenceDiagram
AbstractApplicationContext->>AbstractApplicationContext:refresh
AbstractApplicationContext->>AbstractApplicationContext:finishBeanFactoryInitialization
AbstractApplicationContext->>DefaultListableBeanFactory:preInstantiateSingletons
DefaultListableBeanFactory->>DefaultListableBeanFactory:getBean.......

AbstractAutoProxyCreator因继承SmartInstantiationAwareBeanPostProcessor,重写了postProcessAfterInitialization,让每个bean实例化后进入这里判断

AbstractAutoProxyCreator

1
2
3
4
5
6
7
8
9
10
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

wrapIfNecessary

判断是否要初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
//判断bean是否在postProcessBeforeInstantiation()中成功创建的代理对象都会将beanName加入到targetSourceBeans中。
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
//对于实现了Advice,Advisor,AopInfrastructureBean接口的bean
//都认为是spring aop的基础框架类,不能对他们创建代理对象,同时子类也可以覆盖shouldSkip方法来指定不对哪些bean进行代理。
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}


Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
//判断当前bean是否需要进行代理,若需要则返回满足条件的Advice或者Advisor集合。
//根据getAdvicesAndAdvisorsForBean()方法的具体实现的不同,AbstractAutoProxyCreator又分成了两类自动代理机制。

if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);

//若需要代理,则调用createProxy方法创建代理对象,并将创建的代理的key缓存起来,避免重复创建
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}

this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

createProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//创建ProxyFactory实例,并复制当前类的相关配置

if (!proxyFactory.isProxyTargetClass()) {
//检查当前类是否有实现基于类的代理,还是基于接口,以此来决定是否采用cglib来创建代理对象。
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}



Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//整理合并Advisor,这里AbstractAutoProxyCreator定义了属性interceptorNames用于设置拦截器
//同时子类通过getAdvicesAndAdvisorsForBean()方法也可以返回一组Advisor,
//buildAdvisors()方法就是整理合并这些切面。
//至于调用的先后顺序,通过applyCommonInterceptorsFirst参数可以进行设置
//若applyCommonInterceptorsFirst为true,interceptorNames属性指定的Advisor优先调用。默认为true;


for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}

proxyFactory.setTargetSource(targetSource);


customizeProxyFactory(proxyFactory);
//通过customizeProxyFactory()方法,子类可以对proxyFactory进行设置更改。

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}

//最后调用proxyFactory.getProxy()方法返回代理对象。
return proxyFactory.getProxy(getProxyClassLoader());
}

proxyFactory.getProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
proxyFactory.getProxy(getProxyClassLoader());
|
|
createAopProxy().getProxy(classLoader); //创建代理工厂去进行代理对象
|
|
DefaultAopProxyFactory.createAopProxy
**/




public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

JdkDynamicAopProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;

TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;

try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}

Object retVal;

if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}

target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}

Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}

ObjenesisCglibAopProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// CglibAopProxy.getProxy

public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}

try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}

validateClassIfNecessary(proxySuperClass, classLoader);

Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);

return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Exception ex) {
throw new AopConfigException("Unexpected AOP exception", ex);
}
}



//ObjenesisCglibAopProxy.createProxyClassAndInstance

protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = null;

if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}

if (proxyInstance == null) {
try {
proxyInstance = (this.constructorArgs != null ?
proxyClass.getConstructor(this.constructorArgTypes).newInstance(this.constructorArgs) :
proxyClass.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}

((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}

MVC

img

根据http请求选择合适的controller是MVC中一项十分关键的功能

  • SimpleUrlHandlerMapping //使用定义在spring应用上下文的属性集合,将控制器映射到url上
  • RequestMappingHandlerMapping //使用@RequestMapping注解以前叫DefaultAnnotationHandlerMapping
  • ControllerClassNameHandlerMapping //使用控制器的类名作为URL基础将控制器映射到URL上
  • ControllerBeanNamHandlerMapping //根据控制器Bean的名字作为URL基础将控制器映射到URL上

获取相关的handler,HandlerExecutionChain(执行链)

DispatcherServlet 初始化体系

EmbeddedWebApplicationContext中selfInitialize
当TomcatEmbeddedServletContainer初始化到最后一层Wrapper后调用selfInitialize添加servlet,filter
后期各类pipeline的vavle一直从server->service->engine->host->context->wrapper->filterChain->servlet
其他HandlerMapping如:SimpleUrl,RequestMapping等会等到AbstractApplicationContext#finishBeanFactoryInitialization实例化
执行各类HandlerMapping#afterPropertiesSet—>initHandlerMethods为每个method添加到相关的handlerMapping

selfInitialize
初始化方法,wrapper最后会进行这个selfInitialize

1
2
3
4
5
6
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}

//ServletRegistrationBean 专门注册Servlet
//FilterRegistractionBean 专门注册Filter

由此bean的onStartUp展开了对dispatcher的加载

ServletRegistrationBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
ServletRegistrationBean#onStartup

public void onStartup(ServletContext servletContext) throws ServletException {
String name = getServletName();

.....

Dynamic added = servletContext.addServlet(name, this.servlet);
//this.servlet = dispatcherServlet
//servletContext就是Tomcat的context组件

configure(added);
}


private ServletRegistration.Dynamic addServlet(String servletName,
String servletClass, Servlet servlet) throws IllegalStateException {

//context就是Tomcat的Context的组件为StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]
Wrapper wrapper = (Wrapper) context.findChild(servletName);

if (wrapper == null) {
wrapper = context.createWrapper();
wrapper.setName(servletName);
context.addChild(wrapper);
} else {
if (wrapper.getName() != null &&
wrapper.getServletClass() != null) {
if (wrapper.isOverridable()) {
wrapper.setOverridable(false);
} else {
return null;
}
}
}

if (servlet == null) {
wrapper.setServletClass(servletClass);
} else {
wrapper.setServletClass(servlet.getClass().getName());
wrapper.setServlet(servlet);
}

return context.dynamicServletAdded(wrapper);
}

FilterRegistrationBean

1
2
3
4
5
6
7
8
9
10
AbstractFilterRegistrationBean#onStartup

public void onStartup(ServletContext servletContext) throws ServletException {
Filter filter = getFilter();
String name = getOrDeduceName(filter);

FilterRegistration.Dynamic added = servletContext.addFilter(name, filter);

configure(added);
}

建立体系

RequestMappingHandlerMapping

RequestMappingHandlerMapping继承了InitializingBean实现了afterPropertiesSet

往上一级 AbstractHandlerMethodMapping
super.afterPropertiesSet();
执行initHandlerMethods();->detectHandlerMethods->getMappingForMethod->registerHandlerMethod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//handlerMethod的注册操作  
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}

//从springMVC容器中获取所有的beanName
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));

//注册从容器中获取的beanName
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}



protected void detectHandlerMethods(final Object handler) {
//获取bean实例
Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());

final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
final Class<?> userType = ClassUtils.getUserClass(handlerType);

Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
@Override
public boolean matches(Method method) {
//创建RequestMappingInfo
T mapping = getMappingForMethod(method, userType);
if (mapping != null) {
mappings.put(method, mapping);
return true;
}
else {
return false;
}
}
});

for (Method method : methods) {
registerHandlerMethod(handler, method, mappings.get(method));
}
}


//注册beanName和method及RequestMappingInfo之间的关系,RequestMappingInfo会保存url信息
@Deprecated
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}



@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
}
return info;
}



private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class<?> ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}


//这样就简单实现了将 url 和 HandlerMethod 的对应关系注册到 mappingRegistry 中。
//MappingRegistry中的注册实现如下,并且MappingRegistry定义了几个map结构,用来存储注册信息
private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();

private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();

private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();

private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<String, List<HandlerMethod>>();

private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();



//注册beanName和method及RequestMappingInfo之间的关系,RequestMappingInfo中有url信息
public void register(T mapping, Object handler, Method method) {

this.readWriteLock.writeLock().lock();
try {
//创建HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);

if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//保存url和handlerMethod之间的对应关系
this.mappingLookup.put(mapping, handlerMethod);
//保存url和RequestMappingInfo对应关系
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}

String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}

CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}

this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}


RequestMappingHandlerAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();

if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
  • 初始化各类argumentResolvers
  • 初始化各类returnValueHandlers


忽略ViewName视图解析,Json数据返回

1
2
3
4
5
6
7
8
9
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
  • mavContainer.setRequestHandled(true); 设置true

    • RequestMappingHandlerAdapter#getModelAndView直接返回空的ModelAndView

      1
      2
      3
      if (mavContainer.isRequestHandled()) {
      return null;
      }
    • applyDefaultViewName如果mv==null就不设置viewName了

      1
      2
      3
      4
      5
      private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
      if (mv != null && !mv.hasView()) {
      mv.setViewName(getDefaultViewName(request));
      }
      }
  • writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);:会进行HttpMessageConverter#write操作,直接将信息write出去

    • FastJsonHttpMessageConverterHttpMessageConverter实现类
    • FastJsonHttpMessageConverterHttpMessageConverter实现类


主体流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
DispatcherServlet


--->doService--->doDispatcher()

---->mappedHandler = getHandler(request):
// 从各类HandlerMapping里获取合适的Handler->从mappingRegistry拿之前初始化注册的
// 再拼装各类addInterceptor, 追加CorsInterceptor, 形成HandlerExecutionChain返回

---->getHandlerAdapter(mappedHandler.getHandler());
// 选取合适的HandlerAdapter

----->mappedHandler.applyPreHandle
// Intercetptor前置执行

-----> ha.handle(processedRequest, response, mappedHandler.getHandler());
// 执行主体逻辑
-----> handleInternal----> invokeHandlerMethod
// 封装invocableMethod 元素`argumentResolvers`,`returnValueHandlers`
------> invokeAndHandle -----> invokeForRequest
-----> getMethodArgumentValues //参数解析
-----> doInvoke //反射调用
-------> returnValueHandlers //返回值分装

-----> applyDefaultViewName(processedRequest, mv);
// 视图解析,如果mv为null则不必要解析View

----->mappedHandler.applyPreHandle
// Intercetptor前置执行

获取处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
//
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}


public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//主要获取handler
//getHandlerInternal--->lookupHandlerMethod--->mappingRegistry里获取相关信息(之前也从注册于此)
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}

if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}

//执行链再此形成
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}

执行流程

DispatcherServlet->>DispatcherServlet:doDispatch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
|
|
|
return handleInternal(request, response, (HandlerMethod) handler);
|
|
|
mav = invokeHandlerMethod(request, response, handlerMethod);
|
|
|
######## ServletInvocableHandlerMethod ########
invocableMethod.invokeAndHandle(webRequest, mavContainer);
|
|
|
######## InvocableHandlerMethod ########
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
|
|
|
Object returnValue = doInvoke(args);

HandlerMapping:处理器映射器

作用:根据【请求】找到【处理器Handler】,但并不是简单的返回处理器,而是
将处理器和拦截器封装,形成一个处理器执行链(HandlerExecuteChain)。

HandlerExecuteChain包含以下:

  • interceptorList: 拦截器列表
  • handler: 执行器

DispatcherServlet 拿着执行链去寻找对应的处理器适配器(HandlerAdapter)

为什么要引入适配器?

因为处理器(Handler)有很多种,DispatcherServlet没办法统一管理,所以出现了适配器。

让适配器统一处理Handler,而DispatcherServlet统一处理适配器。

根据请求去找对应的handler






SpringBoot

自动配置

img

img

可以发现其最终实现了ImportSelector(选择器)和BeanClassLoaderAware(bean类加载器中间件)

img

重点关注一下AutoConfigurationImportSelector的selectImports方法

img

img

img

img

img

最终会根据@ConditionOnXXX各类条件



SpringApplication#run Boot启动函数

SpringApplication.run()会启动一个AnnotationConfigEmbeddedWebApplicationContext

如果是SpringCloud项目会在environmentPrepared函数作用下通过消息引导BootstrapApplicationListenerAnnotationConfigApplicationContext应用上下文,后期再启AnnotationConfigEmbeddedWebApplicationContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
  • 环境整理:prepareEnvironment,主要设定webEnvironment并执行预设环境的listener
  • 创建上下文context:AnnotationConfigEmbeddedWebApplicationContext
  • 刷新上下文context:refreshContext
  • 结束刷新上下文context: 主要去调用一些接口实现ApplicationRunner,CommandLineRunner

EmbeddedWebApplicationContext#onRefresh Spring上下文初始化+Servlet容器创造

AbstractApplicationContext#refresh—>AnnotationEmbeddedWebApplication#onRefresh—>EmbeddedWebApplicationContext##onRefresh

创建Servlet容器

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void onRefresh() {
super.onRefresh();
try {
createEmbeddedServletContainer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start embedded container",
ex);
}
}

createEmbeddedServletContainer 创建内部Servlet容器

具体步骤

  • 获取ServletContainer工厂类
  • 从工厂类获取ServletContainer
  • ServletContainer获取的时候会实例化各个tomcat组件

getEmbeddedServletContainerFactory 获取Servlet容器工厂类

获取当前环境下的ServletContainer工厂类,默认为tomcatEmbeddedServletContainerFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//EmbeddedWebApplicationContext#getEmbeddedServletContainerFactory
//获取到当前的tomcatEmbeddedServletContainerFactory的servletContainer工厂类

protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {
String[] beanNames = getBeanFactory()
.getBeanNamesForType(EmbeddedServletContainerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException(
"Unable to start EmbeddedWebApplicationContext due to missing "
+ "EmbeddedServletContainerFactory bean.");
}
if (beanNames.length > 1) {
throw new ApplicationContextException(
"Unable to start EmbeddedWebApplicationContext due to multiple "
+ "EmbeddedServletContainerFactory beans : "
+ StringUtils.arrayToCommaDelimitedString(beanNames));
}
return getBeanFactory().getBean(beanNames[0],
EmbeddedServletContainerFactory.class);
}

containerFactory.getEmbeddedServletContainer(getSelfInitializer()); 工厂类获取Servlet容器

  • 丢初始化函数
  • tomcatEmbeddedServletContainerFactory获取Servlet容器

getSelfInitializer

设置初始化函数,给以后各个Servlet进行OnStartUp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
return new ServletContextInitializer() {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
selfInitialize(servletContext);
}
};
}

private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareEmbeddedWebApplicationContext(servletContext);
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
beanFactory);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
getServletContext());
existingScopes.restore();
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
getServletContext());
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}

getEmbeddedServletContainer

Tomcat准备

  • 实例化Tomcat,并设置setBaseDir(/var/folders/dd/hx_wl3v56_l_bb49fkyd759h0000gn/T/tomcat.7376236981941697730.8171)
  • 实例化Connector,并设置protocolHandlerorg.apache.coyote.http11.Http11NioProtocol
  • Tomcat的Service关联相关的Connector:tomcat.getService().addConnector(connector);
    • tomcat.getService()会实例化StandardServerStandardService,并server.addService(service)把service添加到server
    • 从tomcat的server返回此Service并且添加一个Connector
  • configureEngine(tomcat.getEngine());Engine并配置Engine

    • ServiceContainer有则返回无则实例化StandardEngine并添加service:

      1
      在TomcatEmbeddedServletContainer中Service的Container就是StandardEngine
    • 配置Engine

      1
      engine.getPipeline().addValve(engineValves);
  • prepareContext(tomcat.getHost(), initializers);预设上下文

    • Engine中取Host如若存在则返回,否则实例化StandardHost并添加到Engine

      1
      "localhost" -> "StandardEngine[Tomcat].StandardHost[localhost]"
    • 整理TomcatEmbeddedContext,添加各类listener

获取Tomcat的Servlet容器TomcatEmbeddedServletContainer

return getTomcatEmbeddedServletContainer(tomcat);

实例化TomcatEmbeddedServletContainer
并在构造函数初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private void initialize() throws EmbeddedServletContainerException {
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
try {
//遍历之前各个service下的connectors并clone一份新的放入serviceConnectors的map中然后service.removeConnector(connector);
removeServiceConnectors();

//开启服务并触发各类监听器
this.tomcat.start();

rethrowDeferredStartupExceptions();

//寻找上下文并设置类加载器
Context context = findContext();
try {
ContextBindings.bindClassLoader(context, getNamingToken(context),
getClass().getClassLoader());
}
catch (NamingException ex) {
}

startDaemonAwaitThread();
}
catch (Exception ex) {
containerCounter.decrementAndGet();
throw ex;
}
}
catch (Exception ex) {
throw new EmbeddedServletContainerException(
"Unable to start embedded Tomcat", ex);
}
}
}

接下来相关Tomcat具体的步骤由Tomcat篇目解答



Jar-in-Jar Jar Launcher

1
2
3
4
5
6
maven打包之后,会生成两个jar文件:
demo-0.0.1-SNAPSHOT.jar
demo-0.0.1-SNAPSHOT.jar.original
demo-0.0.1-SNAPSHOT.jar.original是默认的maven-jar-plugin生成的包。

demo-0.0.1-SNAPSHOT.jar是spring boot maven插件生成的jar包,里面包含了应用的依赖,以及spring boot相关的类称之为fat jar。

组织架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
├── BOOT-INF
│   ├── classes
│   │   ├── application.properties
│   │   └── cn
│   │   └── coderss
│   │   └── reactive
│   │   ├── WebApplication.class
│   │   ├── bean
│   │   │   ├── BO
│   │   │   │   ├── IndexBO$IndexBOBuilder.class
│   │   │   │   └── IndexBO.class
│   │   │   ├── DO
│   │   │   │   ├── UserDO$UserDOBuilder.class
│   │   │   │   └── UserDO.class
│   │   │   └── VO
│   │   │   ├── IndexVO$IndexVOBuilder.class
│   │   │   ├── IndexVO.class
│   │   │   ├── UserVO$UserVOBuilder.class
│   │   │   └── UserVO.class
│   │   ├── config
│   │   │   ├── WebMvcConfig.class
│   │   │   └── handler
│   │   │   ├── ObservableReturnValueHandler$ObservableAdapter.class
│   │   │   └── ObservableReturnValueHandler.class
│   │   ├── controller
│   │   │   ├── IndexController.class
│   │   │   ├── OtherController.class
│   │   │   └── UserController.class
│   │   ├── dao
│   │   │   └── UserRepository.class
│   │   └── service
│   │   ├── IIndexService.class
│   │   ├── IUserService.class
│   │   └── impl
│   │   ├── IndexServiceImpl.class
│   │   └── UserServiceImpl.class
│   └── lib
│   ├── bson-3.6.4.jar
│   ..........
│   └── validation-api-2.0.1.Final.jar
├── META-INF
│   ├── MANIFEST.MF
│   └── maven
│   └── cn.coderss
│   └── reactive
│   ├── pom.properties
│   └── pom.xml
└── org
└── springframework
└── boot
└── loader
├── ExecutableArchiveLauncher$1.class
├── ExecutableArchiveLauncher.class
├── JarLauncher.class
........
├── PropertiesLauncher.class
├── WarLauncher.class
├── archive
│   ├── Archive$Entry.class
........
│   └── JarFileArchive.class
├── data
│   ├── ByteArrayRandomAccessData.class
...........
│   └── RandomAccessDataFile.class
├── jar
│   ├── AsciiBytes.class
...........
│   └── ZipInflaterInputStream.class
└── util
└── SystemPropertyUtils.class

Spring-Boot-Loader简介

Springboot中jar文件格式固定如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
archive.jar
|
+-META-INF(1)
| +-MANIFEST.MF
+-org(2)
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-com(3)
| +-mycompany
| + project
| +-YouClasses.class
+-lib(4)
+-dependency1.jar
+-dependency2.jar
  • 结构(1)jar文件中MANIFEST.MF文件存放处
  • 结构(2) Spring-boot-loader本身需要的class放置处
  • 结构(3) 应用本身的文件放置处
  • 结构(4)应用依赖的jar固定放到lib目录。

那么spring-boot是如何去按照这个结构加载资源那?

  • 首先在打包时候会使用spring-boot-maven-plugin插件重写打成的jar文件,会设置META-INF/MANIFEST.MF中的
    Main-Class: org.springframework.boot.loader.JarLauncher
    Start-Class: com.mycompany.project.MyApplication
    并拷贝spring-boot-loader包里面的class文件到结构(2),应用依赖拷贝到(4)应用类拷贝到(3)
  • 通过java -jar archive.jar 运行时候Launcher会去加载JarLauncher类并执行其中的main函数,JarLauncher主要关心构造一个合适的URLClassLoader加载器用来调用我们应用程序(MyApplication)的main方法。

spring-boot-maven-plugin打包流程

img

JarLauncher执行流程分析

img

如流程图首先使用Appclassloader加载了JarLauncher类并创建了LaunchedURLClassLoader类

而LaunchedURLClassLoader是属于spring-boot-loader.jar包里面的

而Appclassloader是普通的加载器不能加载嵌套的jar里面的文件

所以如果把spring-boot-loader.jar放到lib 目录下,Appclassloader将找不到LaunchedURLClassLoader。

所以在打包时候 拷贝本来应该放入到lib里面的spring-boot-loader.jar里面的class到结构(2)

LaunchedURLClassLoader

LaunchedURLClassLoader和普通的URLClassLoader的不同之处是,它提供了从JarFile里加载.class的能力。结合Archive提供的getEntries函数,就可以获取到JarFile里的Resource。

1
2
Jar URL
jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/com/example/SpringBootDemoApplication.class

jar包里的资源的URL;可以看到对于Jar里的资源,定义以’!/’来分隔。原始的JarFile URL只支持一个’!/’。

Spring boot扩展了这个协议,让它支持多个’!/’,就可以表示jar in jar,jar in directory的资源了。

1
2
Jar URL
jar:file:/tmp/target/demo-0.0.1-SNAPSHOT.jar!/lib/spring-beans-4.2.3.RELEASE.jar!/META-INF/MANIFEST.MF

Spring boot通过注册了一个自定义的Handler类来处理多重jar in jar的逻辑。

自定义URLStreamHandler,扩展JarFile和JarURLConnection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//org.springframework.boot.loader.jar.Handler
public class Handler extends URLStreamHandler {
private static final String SEPARATOR = "!/";
private static SoftReference<Map<File, JarFile>> rootFileCache;
@Override
protected URLConnection openConnection(URL url) throws IOException {
if (this.jarFile != null) {
return new JarURLConnection(url, this.jarFile);
}
try {
return new JarURLConnection(url, getRootJarFileFromUrl(url));
}
catch (Exception ex) {
return openFallbackConnection(url, ex);
}
}
public JarFile getRootJarFileFromUrl(URL url) throws IOException {
String spec = url.getFile();
int separatorIndex = spec.indexOf(SEPARATOR);
if (separatorIndex == -1) {
throw new MalformedURLException("Jar URL does not contain !/ separator");
}
String name = spec.substring(0, separatorIndex);
return getRootJarFile(name);
}
}

Spring boot构造LaunchedURLClassLoader时,传递了一个URL[]数组。数组里是lib目录下面的jar的URL

实际流程如下:

  • LaunchedURLClassLoader.loadClass
  • URL.getContent()
  • URL.openConnection()
  • Handler.openConnection(URL)

    最终调用的是JarURLConnectiongetInputStream()函数。

1
2
3
4
5
6
7
8
9
//org.springframework.boot.loader.jar.JarURLConnection
@Override
public InputStream getInputStream() throws IOException {
connect();
if (this.jarEntryName.isEmpty()) {
throw new IOException("no entry name specified");
}
return this.jarEntryData.getInputStream();
}

总结

从一个URL,到最终读取到URL里的内容,整个过程是比较复杂的,总结下:

  • spring boot注册了一个Handler来处理”jar:”这种协议的URL
  • spring boot扩展了JarFile和JarURLConnection,内部处理jar in jar的情况
  • 在处理多重jar in jar的URL时,spring boot会循环处理,并缓存已经加载到的JarFile
  • 对于多重jar in jar,实际上是解压到了临时目录来处理,可以参考JarFileArchive里的代码
  • 在获取URL的InputStream时,最终获取到的是JarFile里的JarEntryData



Reactive

Servlet3.1异步机制

  • 一个ServletRequest可以通过调用 request.startAsync()被放到一个异步的模块中.这样做的主要作用是Servlet,以及任何过滤器,可以退出,但是响应仍将允许开放直到处理完成后。
  • 调用request.startAsync()返回AsyncContext可以用于进一步控制异步处理。例如,它提供一个方法叫dispatch,这个类似于Servlet API,并且它允许应用程序通过Servlet容器线程继续请求处理。
  • ServletRequest提供获取当前DispatcherType的接口.DispatcherType可以用来区分处理初始请求,一个异步分发,forward,以及其他分发类型。

记住上面的,下面是通过Callable异步请求处理事件的序列:

  • Controller返回一个Callable对象.
  • Spring MVC开始异步处理并且提交CallableTaskExecutor在一个单独的线程中进行处理。
  • DispatcherServlet与所有的Filter的Servlet容器线程退出,但Response仍然开放。
  • Callable产生结果并且Spring MVC分发请求给Servlet容器继续处理.
  • DispatcherServlet再次被调用并且继续异步的处理由Callable产生的结果

DeferredResult的处理顺序与Callable十分相似,由应用程序多线程产生异步结果:

  • Controller返回一个DeferredResult对象,并且把它保存在内在队列当中或者可以访问它的列表中。
  • Spring MVC开始异步处理.
  • DispatcherServlet与所有的Filter的Servlet容器线程退出,但Response仍然开放。
  • application通过多线程返回DeferredResult中sets值.并且Spring MVC分发requestServlet容器
  • DispatcherServlet再次被调用并且继续异步的处理产生的结果.

异步支持模式

SpringMVC对Servlet3异步请求的支持有两种方式

  • Callable

    1
    2
    3
    返回方法是Callable类型时会默认发起异步请求
    并使用一个TaskExecutor来调用返回的Callable
    之后的处理就跟正常的SpringMVC请求是一样的
    1
    2
    3
    4
    5
    6
    7
    @GetMapping("callable")
    public Callable<String> callable(){
    return ()->{
    TimeUnit.SECONDS.sleep(1);
    return "callable";
    };
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //执行流程
    RequestMappingHandlerAdapter#handleInternal->RequestMappingHandlerAdapter#invokeHandlerMethod
    ServletInvocableHandlerMethod#invokeAndHandle
    CallableMethodReturnValueHandler#handleReturnValue

    //产生结果并且Spring MVC分发请求给Servlet容器继续处理
    WebAsyncManager#setConcurrentResultAndDispatch
    WebAsyncManager#this.asyncWebRequest.dispatch();

    //Servlet容器拿取结果
    //DispatcherServlet再次被调用并且继续异步的处理产生的结果
    RequestMappingHandlerAdapter#invokeHandlerMethod
    if (asyncManager.hasConcurrentResult()) {
    Object result = asyncManager.getConcurrentResult();
    mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
    asyncManager.clearConcurrentResult();
    if (logger.isDebugEnabled()) {
    logger.debug("Found concurrent result value [" + result + "]");
    }
    invocableMethod = invocableMethod.wrapConcurrentResult(result);
    }
  • DeferredResult

    步骤如上差不多

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @GetMapping("deferredResult")
    public DeferredResult<String> deferredResult(){
    DeferredResult<String> deferredResult = new DeferredResult<>();
    new Thread(() -> deferredResult.setResult("ok")).start();

    deferredResult.onCompletion(()->{
    log.info("completion");
    });
    return deferredResult;
    }

Rxjava+Deferred Result

利用Rxjava的线程调度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("static");
}

@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
returnValueHandlers.add(new ObservableReturnValueHandler());
}
}

public class ObservableReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {

@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
return supportsReturnType(returnType);
}

@Override
public boolean supportsReturnType(MethodParameter returnType) {
return Observable.class.isAssignableFrom(returnType.getParameterType());
}

@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {

final Observable<?> observable = Observable.class.cast(returnValue);
WebAsyncUtils.getAsyncManager(webRequest)
.startDeferredResultProcessing(new ObservableAdapter<>(observable), mavContainer);
}

public class ObservableAdapter<T> extends DeferredResult<T> {
ObservableAdapter(Observable<T> observable) {
observable.subscribe(this::setResult, this::setErrorResult);
}
}
}

@GetMapping("/")
public Observable<IndexVO> index(){
return indexService
.getMessage("San")
.map((data)->IndexVO.builder().message(data.getMessage()).build());
}

异步拦截

一个HandlerInterceptor可样也可以实现AsyncHandlerInterceptor,通过实现它的afterConcurrentHandlingStarted方法进行回调.当进行异步处理的时候,将会调用afterConcurrentHandlingStarted而不是postHandleafterCompletion.

一个HandlerInterceptor同样可以注册CallableProcessingInterceptor或者一个DeferredResultProcessingInterceptor用于更深度的集成异步request的生命周期.例如处理一个timeout事件.你可以参看AsyncHandlerInterceptor的Javadoc了解更多细节.

DeferredResult类也提供了方法,像onTimeout(Runnable)onCompletion(Runnable).可以看DeferredResult了解更多细节.

当使用Callable的时候,你可以通过WebAsyncTask来对它进行包装.这样也可以提供注册timeout与completion方法.

HTTP Streaming

ResponseBodyEmitter允许通过HttpMessageConverter把发送的events写到对象到response中

例如写JSON数据.可是有时候它被用来绕开message转换直接写入到response的OutputStream

例如文件下载.这样可以通过返回StreamingResponseBody类型的值做到.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RequestMapping("/events")
public ResponseBodyEmitter handle() {
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
// Save the emitter somewhere..
return emitter;
}

// In some other thread
emitter.send("Hello once");

// and again later on
emitter.send("Hello again");

// and done at some point
emitter.complete();

转自csdn