Spring源码-阅读笔记
参考文献
- Spring源码深度解析-郝佳
- 极客时间-Spring编程常见错误50例-傅健
环境说明
- spring-framework 5.3x
Spring容器实现
DefaultListableBeanFactory
XmlBeanFeactory
继承自DefaultListableBeanFactory
,而DefaultListableBeanFactory
是整个bean加载的核心部分,是Spring注册及加载bean的默认实现,而对于XmlBeanFeactory
与DefaultListableBeanFactory
不同的地方是在于XmlBeanFactory
中使用了自定义的XML读取器XMLBeanDefinitionReader
,实现了个性化的BeanDefinitionReader
读取,DefaultListableBeanFactory
继承了AbstractAutowireCapableBeanFactory
并实现了ConfigurableListableBeanFactory
以及BeanDefinitionRegistry
接口.
类图中各个类的作用
类名 | 作用 |
---|---|
AliasRegistry |
定义对alias的简单增删改查等操作 |
SimpleAliasRegistry |
主要使用map作为alias的缓存,并对接口AliasRegistry 进行实现 |
SingletonBeanRegistry |
定义对单例的注册及获取 |
BeanFactory |
定义获取Bean及Bean的各种属性 |
DefaultSingletonBeanRegistry |
对接口SingletonBeanRegistry 各函数的实现 |
HierarchicalBeanFactory |
继承BeanFactory ,也就是在BeanFactory 定义的功能的基础上增加了对parentFactory |
BeanDefinitionRegistry |
定义对BeanDefinition 的各种增删改查操作 |
FactoryBeanRegistrySupport |
在DefaultSingletonBeanRegistry 基础上增加了对FactoryBean 的特殊处理功能 |
ConfigurableBeanFactory |
提供配置Factory的各种方法 |
ListableBeanFactory |
根据各种条件获取bean的配置清单 |
AbstractBeanFactory |
综合FactoryBeanRegistrySupport 和ConfigurableBeanFactory 的功能 |
AutowireCapableBeanFactory |
提供创建bean,自动注入,初始化以及应用bean的后处理器 |
AbstractAutowireCapableBeanFactory |
综合AbstractBeanFactory 并对接口AutowireCapableBeanFactory 进行处理 |
ConfigurableListableBeanFactory |
BeanFactory 配置清单,指定忽略类型及接口等 |
DefaultListableBeanFactory |
综合上面所有功能,主要是对Bean注册后的处理 |
DefaultSingletonBeanRegistry
1 | // 一级缓存 用于保存实例化、注入、初始化完成的bean实例 保存BeanName和创建Bean实例之间的关系,bean name-->bean instance |
Bean
的加载过程
入口
1 | org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean |
大致流程
-
转换对应
beanName
1
org.springframework.beans.factory.support.AbstractBeanFactory#transformedBeanName
-
尝试从缓存中加载单例
1
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
-
bean
的实例化1
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
-
原型模式的依赖检查
1
org.springframework.beans.factory.support.AbstractBeanFactory#isPrototypeCurrentlyInCreation
-
检测
parentBeanFactory
1
org.springframework.beans.factory.support.AbstractBeanFactory#getParentBeanFactory
-
将存储
XML
配置文件的GernericBeanDefinition
转换为RootBeanDefinition
1
org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition
-
寻找依赖
1
org.springframework.beans.factory.support.AbstractBeanDefinition#getDependsOn
-
针对不同的
scope
进行bean
的创建1
org.springframework.beans.factory.support.AbstractBeanFactory#createBean
-
类型转换
1
org.springframework.beans.factory.support.AbstractBeanFactory#adaptBeanInstance
FactoryBean
的使用
-
一般情况下,Spring通过反射机制利用Bean的class属性指定实现类来实例化Bean.在某些情况下,实例化Bean过程比较复杂,如果按照传统方式,则需要在
<bean>
中提供大量配置信息,配置方式的灵活是受限的,这时采用编码的方式可能会得到一个简单的方案. -
Spring为此提供了一个
org.springframework.beans.factory.FactoryBean
的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
/**
* 返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中.
*/
T getObject() throws Exception;
/**
* 返回FactoryBean创建的bean类型
*/
Class<?> getObjectType();
/**
* 返回由FactoryBean创建的bean实例的作用域singleton还是prototype
*/
default boolean isSingleton() {
return true;
}
} -
当配置文件中
<bean>
的class属性配置的实现类是FactoryBean
时,通过getBean()
返回的不是FactoryBean
本身,而是FactoryBean#getObject()
方法返回的对象,相当于FactoryBean#getObject()
代理了getBean()
. -
如果希望获取FactoryBean的实例,则需要使用
getBean(beanName)
方法是在beanName前显示的加上**“&”**前缀,如getBean("&beanName")
循环依赖问题
构造器循环依赖
- 不支持,抛出
BeanCurrentlyInCreationException
异常
setter
循环依赖
- 依赖Spring的三级缓存解决
prototype
范围的依赖处理
- 不支持,抛出
BeanCurrentlyInCreationException
异常
简言之,两个池子:一个成品池子,一个半成品池子。能解决循环依赖的前提是:spring开启了allowCircularReferences,那么一个正在被创建的bean才会被放在半成品池子里。在注入bean,向容器获取bean的时候,优先向成品池子要,要不到,再去向半成品池子要。
出现循环依赖一定是你的业务设计有问题。高层业务和底层业务的划分不够清晰,一般,业务的依赖方向一定是无环的,有环的业务,在后续的维护和拓展一定非常鸡肋.
BeanPostProcessor
和BeanFactoryPostProcessor
BeanPostProcessor
BeanFactoryPostProcessor
BeanFactoryPostProcessor
接口和BeanPostProcessor
类似,可以对Bean定义(配置元数据)进行处理.也就是说,Spring IoC容器允许BeanFactoryPostProcessor
在容器实际实例化任何其他bean之前读取配置元数据,并有可能修改它.- 可以配置多个
BeanFactoryPostProcessor
,也可以通过order
属性来控制BeanFactoryPostProcessor
的执行顺序(仅当BeanFactoryPostProcessor
实现了Ordered
接口时才可以设置此属性,因此在实现BeanFactoryPostProcessor
时,应当考虑实现Ordered
接口). - 若想要改变实际的Bean实例(例如从配置元数据创建的对象),那么最好使用
BeanPostProcessor
BeanFactoryPostProcessor
的作用域范围是容器级的.它只和所使用的容器有关.- 典型应用:
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
AOP
动态AOP
静态AOP
AOP
的静态代理主要是在虚拟机启动时通过改变目标对象字节码的方式来完成对目标对象的增强.- 它与动态代理相比具有更高的效率,因为在动态代理调用的过程中,还需要动态创建代理类并代理目标对象的步骤,而静态代理则是在启动时便完成了字节码增强,当系统再次调用目标类时域调用正常的类并无差别,所以在效率上会相对高些.
Instrumentation
使用
-
Java在1.5引入
java.lang.instrument
,可以由此实现一个Java agent
,通过agent
来修改类的字节码即改变一个类. -
写
ClassFileTransformer
类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
44package com.holelin.sundry.utils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.NotFoundException;
public class PerfMonXformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] transformed = null;
System.out.println("Transforming" + className);
final ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.makeClass(new ByteArrayInputStream(classfileBuffer));
if (cl.isInterface() == false) {
final CtBehavior[] methods = cl.getDeclaredBehaviors();
for (int i = 0; i < methods.length; i++) {
if (methods[i].isEmpty() == false) {
doSomeThing(methods[i]);
}
}
transformed = cl.toBytecode();
}
} catch (IOException | CannotCompileException e) {
System.out.println("Cloud not instrument " + className + ", exception : " + e.getMessage());
} catch (NotFoundException e) {
throw new RuntimeException(e);
}
return transformed;
}
private void doSomeThing(CtBehavior method) throws NotFoundException,CannotCompileException{
method.insertBefore("long stime = System.nanoTime();");
method.insertAfter("System.out.println(\"leave \"+method.getName()+\" and time: \"+(System.nanoTime() -stime));");
} -
编写
agent
类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
26package com.holelin.sundry.utils;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
/**
* @Description:
* @Author: HoleLin
* @CreateDate: 2022/8/25 12:56
* @UpdateUser: HoleLin
* @UpdateDate: 2022/8/25 12:56
* @UpdateRemark: 修改内容
* @Version: 1.0
*/
public class PerfMonAgent {
private static Instrumentation inst = null;
public static void permain(String agentArgs, Instrumentation _inst) {
System.out.println("PerfMonAgent.permain() was called.");
inst = _inst;
ClassFileTransformer transformer = new PerfMonXformer();
System.out.println("Adding a PerfMonxformer instance to the JVM");
inst.addTransformer(transformer);
}
} -
打包
agent
- JAR的
META-INF/MANIFEST.MF
加入Permain-Class:xx
,xx
即上面实现的agent
类 - 若
agent
类引入了其他的包,则需要使用Boot-Class-Path:xx
,xx
即JBoss javassit
- JAR的
源码阅读入口
名称 | 入口 |
---|---|
@ComponentScan |
org.springframework.context.annotation.ComponentScanAnnotationParser#parse |
@Lookup |
org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor#intercept |
Bean 命名规则 |
BeanNameGenerator#generateBeanName |
@Value |
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver.getSuggestedValue |
@PostConstruct |
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor |
InitializingBean 接口 |
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods |
annotation-driven | org.springframework.transaction.config.TxNamespaceHandler |
@Import /@Configuration |
org.springframework.context.annotation.ConfigurationClassPostProcessor |
org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
类处理@Component
@PropertySources
@ComponentScans
,@ComponentScan
@Import
@ImportResource
@Bean
关于Spring AOP
增强
- 在同一个切面配置中,如果存在多个不同类型的增强,那么其执行优先级是按照增强类型的特定顺序排列,依次的增强类型为
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
; - 在同一个切面配置中,如果存在多个相同类型的增强,那么其执行优先级是按照该增强的方法名排序,排序方式依次为比较方法名的每一个字母,直到发现第一个不相同且 ASCII 码较小的字母。较小的优先被执行.
源码追踪路径
1 | org.springframework.aop.config.AopNamespaceHandler#init |
静态AOP源码追踪
1 | org.springframework.context.config.ContextNamespaceHandler#init |
关于Spring Transaction
源码追踪路径
1 | 1. org.springframework.transaction.config.TxNamespaceHandler#init |
- 事务传播处理方法:
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
关于Spring MVC
源码追踪路径
org.springframework.web.context.ContextLoaderListener
ContextLoaderListener
的作用就是启动Web容器时,自动装配ApplicationContext
的配置信息.因为它实现了ServletContextListener
接口,在配置web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法,使用ServletContextListener
接口,开发者能够在为客户端请求提供服务之前向ServletContext
中添加任意的对象.这个对象在ServletContext
启动的时候被初始化,然后在ServletContext
整个运行期间都是可见的.ServletContext
启动之后会调用ServletContextListener
的contextInitialized
方法
1 | 1. javax.servlet.ServletContextListener |
org.springframework.web.servlet.DispatcherServlet
servlet
的生命周期是有servlet
的容器来控制的,它可以分为3个阶段: 初始化,运行和销毁.- 初始化阶段
servlet
容器加载servlet
类,把servlet
的.class
文件中的数据读到内存中.servlet
容器创建一个ServletConfig
对象.ServletConfig
对象包含了servlet
的初始化配置信息.servlet
容器创建一个servlet
对象.servlet
容器调用servlet
对象的init
方法进行初始化.
- 运行阶段
- 当
servlet
容器收到一个请求时,servlet
容器会针对这个请求创建servletRequest
和servletResponse
对象,然后调用service
方法.并把这两个参数传递给service
方法.service
方法通过servletRequest
对象获得请求的信息,并处理该请求,再通过servletResponse
对象生成这个请求的响应结果.然后销毁servletRequest
和servletResponse
对象.
- 当
- 销毁阶段
- 当Web 应用被终止时,
servlet
容器会先调用servlet
对象的destrory
方法,然后再销毁servlet
对象,同时也会销毁与servlet
对象相关联的servletConfig
对象。 我们可以在destroy
方法的实现中,释放servlet
所占用的资源,如关闭数据库连接,关闭文件输入输出等. - servlet 的框架是由两个 Java 包组成:
javax.servlet
和javax. servlet.http
。 在javax.servlet
包中定义了所有的servlet
类都必须实现或扩展的通用接口和类,在javax.servlet.http
即包中定义了采用HTTP通信协议的HttpServlet
类. servlet
被设计成请求驱动,servlet
的请求可能包含多个数据项,当 Web 容器接收到某个servlet
请求时,servlet
把请求封装成一个HttpServletRequest
对象,然后把对象传给servlet
的对应的服务方法.
- 当Web 应用被终止时,
- 初始化阶段