Spring 源码学习

/ 技术文章 / 0 条评论 / 1180浏览

Spring 源码学习

面试常问问题:

  1. IOC, 反射
  2. AOP, 动态代理(JDK, cglib)
  3. 循环依赖
  4. Bean生命周期

IOC和DI是什么?

BeanFactory 和 FactoryBean的区别?

BeanFactory和ApplicationContext的异同

BeanFactory

相同:

不同:

Environment

当前上下文运行的环境,存储着各种全局变量。这些变量会影响着当前程序的运行情况(比如JDK信息、磁盘信息、内存信息等等。当然还包括用户自定义的一些属性值)。

Environment接口继承自PropertyResolver,所以它既能处理属性值、也能处理配置Profile

IOC容器初始化

Spring IOC容器的初始化简单的可以分为三个过程:

  1. 第一个过程是Resource资源定位。这个Resouce指的是BeanDefinition的资源定位。这个过程就是容器找数据的过程,就像水桶装水需要先找到水一样。

  2. 第二个过程是BeanDefinition的载入过程。这个载入过程是把用户定义好的Bean表示成Ioc容器内部的数据结构,而这个容器内部的数据结构就是BeanDefition。

  3. 第三个过程是向IOC容器注册这些BeanDefinition的过程,这个过程就是将前面的BeanDefition保存到HashMap中的过程。

Ioc容器的初始化是由 refresh 方法来启动的,这个方法标志着 IoC 容器的正式启动,具体来说这个启动过程包括三个基本过程:

  1. BeanDifinition 的 Resource 定位

    • 各种格式:XML, Annotation, Yaml,配置类等等
    • ResourceLoader: 路径下的资源可以用 ClassPathResource、网络上的资源可以用 UrlResource。
  2. BeanDifinition 的载入与解析

    • BeanDefinitionReader,可扩展,自定义统一的配置信息的修改
    • getBeanClassName:获取 Bean 的类名称;
    • isLazyInit:是否懒加载;
    • getFactoryBeanName:获取对应的 FactoryBean 的名称;
    • getConstructorArgumentValues:获取构造器参数,可以通过 xml、注解注入;
    • getPropertyValues:获取属性参数,可以通过 xml、注解注入。
  3. BeanDifinition 在 Ioc 容器中的注册

    1. 执行BeanFactoryPostProcessors 增强器
    2. BeanFactory,通过Bean工厂,反射实例化Bean
    3. 注册BeanPostProcessors 增强器
    4. 初始化Bean,执行BeanPostProcessors 增强器, (AOP在执行BeanPostProcessors实现)
    5. 放入Map

Spring Bean 的生命周期

对象创建的方式:

总结:

(1)实例化Bean:

对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

(2)设置对象属性(依赖注入):

实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

(3)处理Aware接口:

接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;

②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

(4)BeanPostProcessor:

如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 与 init-method:

如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

(7)DisposableBean:

当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

(8)destroy-method:

最后,如果这个Bean的Spring配置中配置了destroy-method属性,关闭容器时,会自动调用其配置的销毁方法。

Spring AOP的实现原理?

Spring如何解决循环依赖

A -> B -> C -> A

https://blog.csdn.net/qq_36381855/article/details/79752689

通过三级缓存来解决循环依赖问题,这三级缓存分别指:

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
 
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
 
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

通过缓存构造器的方式解决循环依赖,用来解决setter的循环依赖,因此由构造器的依赖造成的循环 依赖,无法解决,

Spring 是如何管理事务的?

​ Spring事务管理主要包括3个接口,Spring的事务主要是由它们(PlatformTransactionManager,TransactionDefinition,TransactionStatus)三个共同完成的。

1. PlatformTransactionManager:事务管理器--主要用于平台相关事务的管理

主要有三个方法:

2. TransactionDefinition:事务定义信息--用来定义事务相关的属性,给事务管理器PlatformTransactionManager使用

这个接口有下面四个主要方法:

事务管理器能够根据这个返回值进行优化,这些事务的配置信息,都可以通过配置文件进行配置。

3. TransactionStatus:事务具体运行状态--事务管理过程中,每个时间点事务的状态信息。

例如它的几个方法:

声明式事务的优缺点

Spring 中用到了那些设计模式?

bean的作用域

(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。

(2)prototype:为每一个bean请求提供一个实例。

(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。

(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。

Spring框架中有哪些不同类型的事件

(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。

(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。

(5)请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。

Spring通知有哪些类型

(1)前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

(2)返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

(3)抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。

(4)后通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

(5)环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 环绕通知是最常用的一种通知类型。

Spring的自动装配

在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式。

在Spring框架xml配置中共有5种自动装配:

(1)no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。

(2)byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。

(3)byType:通过参数的数据类型进行自动装配。

(4)constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。

(5)autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。

基于注解的方式:

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;

如果查询的结果不止一个,那么@Autowired会根据名称来查找;

如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

@Autowired可用于:构造函数、成员变量、Setter方法

注:@Autowired和@Resource之间的区别

(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。

参考

https://github.com/bjmashibing/java/blob/master/javaframework/spring/08Spring%E6%BA%90%E7%A0%81%E8%AE%B2%E8%A7%A3/06Spring%E5%8E%9F%E7%90%86%E8%AE%B2%E8%A7%A3.md