参考文献

  • Spring源码深度解析-郝佳
  • 极客时间-Spring编程常见错误50例-傅健

环境说明

  • spring-framework 5.3x

Spring容器实现

img

DefaultListableBeanFactory

  • XmlBeanFeactory继承自DefaultListableBeanFactory,而DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载bean的默认实现,而对于XmlBeanFeactoryDefaultListableBeanFactory不同的地方是在于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 综合FactoryBeanRegistrySupportConfigurableBeanFactory的功能
AutowireCapableBeanFactory 提供创建bean,自动注入,初始化以及应用bean的后处理器
AbstractAutowireCapableBeanFactory 综合AbstractBeanFactory并对接口AutowireCapableBeanFactory进行处理
ConfigurableListableBeanFactory BeanFactory配置清单,指定忽略类型及接口等
DefaultListableBeanFactory 综合上面所有功能,主要是对Bean注册后的处理

DefaultSingletonBeanRegistry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 一级缓存 用于保存实例化、注入、初始化完成的bean实例 保存BeanName和创建Bean实例之间的关系,bean name-->bean instance
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// 三级缓存 用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。保存BeanName和创建Bean的工厂之间的关系,bean name-->ObjectFactory
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

// 二级缓存 用于保存实例化完成的bean实例, 保存BeanName和创建Bean实例之间的关系
// 与singletonObjects的不同之处在于,当一个单例Bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到,其目的是用来检测循环引用
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

// 用来保存当前所有已注册的Bean
/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

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
    24
    public interface FactoryBean<T> {

    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    /**
    * 返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中.
    */
    @Nullable
    T getObject() throws Exception;

    /**
    * 返回FactoryBean创建的bean类型
    */
    @Nullable
    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的时候,优先向成品池子要,要不到,再去向半成品池子要。

出现循环依赖一定是你的业务设计有问题。高层业务和底层业务的划分不够清晰,一般,业务的依赖方向一定是无环的,有环的业务,在后续的维护和拓展一定非常鸡肋.

BeanPostProcessorBeanFactoryPostProcessor

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
    44
    package 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 {

    @Override
    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
    26
    package 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,xxJBoss javassit

源码阅读入口

名称 入口
@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
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.aop.config.AopNamespaceHandler#init
org.springframework.aop.config.AspectJAutoProxyBeanDefinitionParser#parse
# 1.注册AnnotationAutoProxyCreator
org.springframework.aop.config.AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary

# 2.创建AOP代理
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
# 1. 获取增强方法或增强器
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
# 获取增强器
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
# 解析标记AspectJ注解的增强方法
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
# 普通增强器获取
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor
org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvice
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
2. 根据获取的增强进行代理
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy

3. 激活增强方法
org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgs

静态AOP源码追踪

1
2
org.springframework.context.config.ContextNamespaceHandler#init
org.springframework.context.config.LoadTimeWeaverBeanDefinitionParser#doPars

关于Spring Transaction

源码追踪路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1. org.springframework.transaction.config.TxNamespaceHandler#init
2. org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser#parse
// 注册 InfrastructureAdvisorAutoProxyCreator
3. org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer#configureAutoProxyCreator
4. org.springframework.aop.config.AopNamespaceUtils#registerAutoProxyCreatorIfNecessary
5. org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary ==> 注册InfrastructureAdvisorAutoProxyCreator类型的Bean
6. org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer#configureAutoProxyCreator ==> 注册TransactionInterceptor类型的Bean以及注册BeanFactoryTransactionAttributeSourceAdvisor类型的Bean
7. org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
8. org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
// 获取对应class/method的增强器
9. org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
10. org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
// 寻找候选增强器
11. org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors ==> org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
// 候选增强器中寻找匹配项
12. org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply ==> org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
13. org.springframework.aop.support.AopUtils#canApply ==> org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)
14. org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches
15. org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute
// 提取事务标签
16. org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute
  • 事务传播处理方法: 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启动之后会调用ServletContextListenercontextInitialized方法
1
2
1. javax.servlet.ServletContextListener
2. org.springframework.web.context.ContextLoaderListener
org.springframework.web.servlet.DispatcherServlet
  • servlet的生命周期是有servlet的容器来控制的,它可以分为3个阶段: 初始化,运行和销毁.
    • 初始化阶段
      • servlet容器加载servlet类,把servlet.class文件中的数据读到内存中.
      • servlet容器创建一个ServletConfig对象.ServletConfig对象包含了servlet的初始化配置信息.
      • servlet容器创建一个servlet对象.
      • servlet容器调用servlet对象的init方法进行初始化.
    • 运行阶段
      • servlet容器收到一个请求时,servlet容器会针对这个请求创建servletRequestservletResponse对象,然后调用service方法.并把这两个参数传递给service方法.service方法通过servletRequest对象获得请求的信息,并处理该请求,再通过servletResponse对象生成这个请求的响应结果.然后销毁servletRequestservletResponse对象.
    • 销毁阶段
      • 当Web 应用被终止时,servlet容器会先调用servlet对象的destrory方法,然后再销毁servlet对象,同时也会销毁与servlet对象相关联的servletConfig对象。 我们可以在destroy方法的实现中,释放servlet所占用的资源,如关闭数据库连接,关闭文件输入输出等.
      • servlet 的框架是由两个 Java 包组成:javax.servletjavax. servlet.http。 在javax.servlet包中定义了所有的servlet类都必须实现或扩展的通用接口和类,在javax.servlet.http即包中定义了采用HTTP通信协议的HttpServlet类.
      • servlet被设计成请求驱动, servlet的请求可能包含多个数据项,当 Web 容器接收到某个servlet 请求时,servlet把请求封装成一个HttpServletRequest对象,然后把对象传给servlet的对应的服务方法.