Spring

Spring体系架构(基于4.x)

框架篇 - 图1

1、Core Container(核心容器)
该模块主要包含Core、Beans、Context和SpEL模块。其中Core和Beans是整个框架最基础的部分,提供IOC和依赖注入特性。这里最重要的概念就是BeanFactory,提供了以Factory模式的实现来消除对程序性
单例模式。

  • Core:模块主要包含Spring框架最基本的核心工具类,Core是其他组件的基础核心。
  • Beans:模块主要包含访问配置文件、创建/管理Bean以及IOC/DI相关的类。
  • Context:继承了Beans的特性,主要为Spring提供大量的扩展,如国际化、事件机制、资源加载等待。ApplicationContext接口是Context模块的关键。
  • SpEL:模块提供了一个强大的语言表达式。

———————————————————————————————————————————————————————
2、AOP and Instrumentation
提供符合AOP Alliance标准的面向切面编程的实现,可以让你定义如方法拦截器和切点,从而降低程序之间的耦合性。

  • AspectJ模块:提供了与AspectJ的集成 。
  • Instrumentation模块:提供用于某些应用程序服务器的类工具支持和类加载器实现 。

———————————————————————————————————————————————————————
3、Messaging
该模块具有来自Spring Integration项目的关键抽象,如Message,MessageChannel,MessageHandler等。它们构成基于消息的应用程序的基础。该模块还包括一组注释,用于将消息映射到方法,类似于基于Spring MVC注释的编程模型。
———————————————————————————————————————————————————————
4、Data Access/Integration
数据访问/集成层由JDBC,ORM,OXM,JMS和事务模块组成。

  • JDBC模块:提供了JDBC抽象层,从而无需进行繁琐的JDBC编码和数据库特定错误代码(不同数据代码可能不同)的解析。
  • 事务模块:支持对实现特殊接口的类以及所有POJO(普通Java对象)进行编程和声明式事务管理。
  • ORM模块:该模块为当前流行的ORM(包括JPA,JDO和Hibernate)提供了集成层。使用ORM模块,可以将所有这些O/R映射框架与Spring提供的所有功能结合使用,如前面提到的事务管理功能。
  • OXM模块:提供了一个抽象层,该抽象层支持Object/ XML映射实现,例如JAXB,Castor,XMLBeans,JiBX和XStream。
  • JMS模块(Java Messaging Service):包含用于生成和使用消息的功能。从Spring Framework 4.1开始,提供了与Spring-Messaging模块集成。

———————————————————————————————————————————————————————
5、Web
Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供上下文支持。该模块包含Web、WebMVC、Web Socket和Web-Porlet模块。

  • Web模块:提供了基本的面向Web的集成功能,如文件上传功能以及使用Servlet监听器和面向Web的应用程序上下文对IoC容器的初始化。
  • WebMVC模块(也称为Web-Servlet模块):包含基于Spring的Model-View-Controller(MVC)支持和针对Web应用程序的Rest Web服务实现。
  • Web-Portlet 模块(也称为Web-Portlet模块):提供Portlet环境中的MVC实现。

———————————————————————————————————————————————————————
6、Test
该模块支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。

IoC

IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC 在其他语言中也有应用,并非 Spring 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。
推荐阅读:https://www.zhihu.com/question/23277575/answer/169698662
Spring IoC的初始化过程:
框架篇 - 图2

1.从xml进行加载,解析为为BeanDefinition
2.注册到BeanFactory

bean的生命周期

在核心方法refresh中体现了bean的生命周期

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. // Prepare this context for refreshing.
  5. // 1.准备刷新上下文环境 声明早期的监听器和事件,不需要手动调用publishEvent
  6. prepareRefresh();
  7. // Tell the subclass to refresh the internal bean factory.
  8. // 2.告诉父类子类初始化Bean工厂
  9. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  10. // Prepare the bean factory for use in this context.
  11. // 3.对bean工厂进行填充属性 注册解析接口方式的监听器的BeanPostProcessor
  12. prepareBeanFactory(beanFactory);
  13. try {
  14. // Allows post-processing of the bean factory in context subclasses.
  15. // 4.留个子类去实现该接口
  16. postProcessBeanFactory(beanFactory);
  17. // Invoke factory processors registered as beans in the context.
  18. // 调用bean工厂的后置处理器
  19. invokeBeanFactoryPostProcessors(beanFactory);
  20. // Register bean processors that intercept bean creation.
  21. // 注册bean的后置处理器
  22. registerBeanPostProcessors(beanFactory);
  23. // Initialize message source for this context.
  24. // 初始化国际资源处理器
  25. initMessageSource();
  26. // Initialize event multicaster for this context.
  27. // 创建事件多播器
  28. initApplicationEventMulticaster();
  29. // Initialize other special beans in specific context subclasses.
  30. // 模板方法,在容器刷新的时候可以自定义逻辑,不同的Spring容器做不同的事情。
  31. onRefresh();
  32. // Check for listener beans and register them.
  33. // 注册监听器,广播early application events
  34. registerListeners();
  35. // Instantiate all remaining (non-lazy-init) singletons.
  36. // 实例化所有剩余的(非懒加载)单例
  37. finishBeanFactoryInitialization(beanFactory);
  38. // Last step: publish corresponding event.
  39. // 最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
  40. finishRefresh();
  41. }
  42. catch (BeansException ex) {
  43. if (logger.isWarnEnabled()) {
  44. logger.warn("Exception encountered during context initialization - " +
  45. "cancelling refresh attempt: " + ex);
  46. }
  47. // Destroy already created singletons to avoid dangling resources.
  48. destroyBeans();
  49. // Reset 'active' flag.
  50. cancelRefresh(ex);
  51. // Propagate exception to caller.
  52. throw ex;
  53. }
  54. finally {
  55. // Reset common introspection caches in Spring's core, since we
  56. // might not ever need metadata for singleton beans anymore...
  57. resetCommonCaches();
  58. }
  59. }
  60. }

对应中文版本:
1.Bean 容器找到配置文件中 Spring Bean 的定义
2.Bean 容器利用 Java Reflection API 创建一个Bean的实例
3.注入值
4.一堆Aware接口
5.BeanPostProcessor前置处理,执行postProcessBeforeInitialization() 方法
6.如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
7.init-method方法
8.BeanPostProcessor后置处理,执行postProcessAfterInitialization() 方法
9.当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
10.当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法
image.png

IoC源码阅读

循环依赖

所谓的循环依赖是指,A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。或者是 A 依赖 B,B 依赖 C,C 又依赖 A。它们之间的依赖关系如下:
框架篇 - 图4

解决方法:
使用缓存,Spring中有三级缓存,如下面这个例子。

  1. /***
  2. * Spring --循环依赖实例DEMO :
  3. * 帮助您更有效的理解Spring循环依赖源码
  4. */
  5. public class MainStart {
  6. private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
  7. /**
  8. * 读取bean定义,当然在spring中肯定是根据配置 动态扫描注册
  9. */
  10. public static void loadBeanDefinitions() {
  11. RootBeanDefinition aBeanDefinition=new RootBeanDefinition(InstanceA.class);
  12. RootBeanDefinition bBeanDefinition=new RootBeanDefinition(InstanceB.class);
  13. beanDefinitionMap.put("instanceA",aBeanDefinition);
  14. beanDefinitionMap.put("instanceB",bBeanDefinition);
  15. }
  16. public static void main(String[] args) throws Exception {
  17. // 加载了BeanDefinition
  18. loadBeanDefinitions();
  19. // 注册Bean的后置处理器
  20. // 循环创建Bean
  21. for (String key : beanDefinitionMap.keySet()){
  22. // 先创建A
  23. getBean(key);
  24. }
  25. InstanceA instanceA = (InstanceA) getBean("instanceA");
  26. instanceA.say();
  27. }
  28. // 一级缓存
  29. public static Map<String,Object> singletonObjects=new ConcurrentHashMap<>();
  30. // 二级缓存: 为了将 成熟Bean和纯净Bean分离,避免读取到不完整得Bean
  31. public static Map<String,Object> earlySingletonObjects=new ConcurrentHashMap<>();
  32. // 三级缓存
  33. public static Map<String,ObjectFactory> singletonFactories=new ConcurrentHashMap<>();
  34. // 循环依赖标识
  35. public static Set<String> singletonsCurrennlyInCreation=new HashSet<>();
  36. // 假设A 使用了Aop @PointCut("execution(* *..InstanceA.*(..))") 要给A创建动态代理
  37. // 获取Bean
  38. public static Object getBean(String beanName) throws Exception {
  39. Object singleton = getSingleton(beanName);
  40. if(singleton!=null){
  41. return singleton;
  42. }
  43. // 正在创建
  44. if(!singletonsCurrennlyInCreation.contains(beanName)){
  45. singletonsCurrennlyInCreation.add(beanName);
  46. }
  47. // createBean
  48. // 实例化
  49. RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
  50. Class<?> beanClass = beanDefinition.getBeanClass();
  51. Object instanceBean = beanClass.newInstance(); // 通过无参构造函数
  52. // 创建动态代理 (耦合 、BeanPostProcessor) Spring还是希望正常的Bean 还是再初始化后创建
  53. // 只在循环依赖的情况下在实例化后创建proxy 判断当前是不是循环依赖
  54. singletonFactories.put(beanName, () -> new JdkProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName),beanName));
  55. // 添加到二级缓存
  56. // earlySingletonObjects.put(beanName,instanceBean);
  57. // 属性赋值
  58. Field[] declaredFields = beanClass.getDeclaredFields();
  59. for (Field declaredField : declaredFields) {
  60. Autowired annotation = declaredField.getAnnotation(Autowired.class);
  61. // 说明属性上面有Autowired
  62. if(annotation!=null){
  63. declaredField.setAccessible(true);
  64. // byname bytype byconstrator
  65. // instanceB
  66. String name = declaredField.getName();
  67. Object fileObject= getBean(name); //拿到B得Bean
  68. declaredField.set(instanceBean,fileObject);
  69. }
  70. }
  71. // 初始化 init-mthod
  72. // 放在这里创建已经完了 B里面的A 不是proxy
  73. // 正常情况下会再 初始化之后创建proxy
  74. // 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
  75. if(earlySingletonObjects.containsKey(beanName)){
  76. instanceBean=earlySingletonObjects.get(beanName);
  77. }
  78. // 添加到一级缓存 A
  79. singletonObjects.put(beanName,instanceBean);
  80. // remove 二级缓存和三级缓存
  81. return instanceBean;
  82. }
  83. public static Object getSingleton(String beanName){
  84. // 先从一级缓存中拿
  85. Object bean = singletonObjects.get(beanName);
  86. // 说明是循环依赖
  87. if(bean==null && singletonsCurrennlyInCreation.contains(beanName)){
  88. bean=earlySingletonObjects.get(beanName);
  89. // 如果二级缓存没有就从三级缓存中拿
  90. if(bean==null) {
  91. // 从三级缓存中拿
  92. ObjectFactory factory = singletonFactories.get(beanName);
  93. if (factory != null) {
  94. bean=factory.getObject(); // 拿到动态代理
  95. //存到二级缓存
  96. earlySingletonObjects.put(beanName, bean);
  97. }
  98. }
  99. }
  100. return bean;
  101. }
  102. }

image.png

image.png
为什么需要二级缓存?
一级缓存无法保证多线程下的一级缓存Bean的完整性

  • 一级缓存和二级缓存相比:

二级缓存只要是为了分离成熟Bean和纯净Bean(未注入属性)的存放, 防止多线程中在Bean还未创建完成时读取到的Bean时不完整的。所以也是为了保证我们getBean是完整最终的Bean,不会出现不完整的情况。

  • 一二三级缓存下二级缓存的意义:

二级缓存为了存储 三级缓存的创建出来的早期Bean, 为了避免三级缓存重复执行。
为什么需要三级缓存?
只用到二级缓存就可以解决循环依赖的问题了,但耦合度大,且多线程下读取性能不高,三级缓存存函数接口, 函数接口实现 创建动态代理调用BeanPostProcessor 。 为了避免重复创建, 调用把返回的动态代理对象或者原实例存储在二级缓存。

Spring是怎样避免读取到不完整Bean的?
使用缓存将完整的(一级缓存)和不完整的Bean(二级缓存)隔离,同时使用了synchronized方法进行同步(多线程下也安全)。

Spring事件

Spring事件体系包括三个组件:事件,事件监听器,事件广播器,使用观察者模式
事件可在最后容器刷新(finishRefresh()) 发布刷新事件(Spring cloud也是从这里启动的),可以在所有Bean创建完后做扩展。

事件
Spring内置事件
内置事件中由系统内部进行发布,只需注入监听器
框架篇 - 图7

Event 说明
ContextRefreshedEvent 当容器被实例化或refreshed时发布.如调用refresh()方法, 此处的实例化是指所有的bean都已被加载,后置处理器都被激活,所有单例bean都已被实例化, 所有的容器对象都已准备好可使用. 如果容器支持热重载,则refresh可以被触发多次(XmlWebApplicatonContext支持热刷新,而GenericApplicationContext则不支持)
ContextStartedEvent 当容器启动时发布,即调用start()方法, 已启用意味着所有的Lifecycle bean都已显式接收到了start信号
ContextStoppedEvent 当容器停止时发布,即调用stop()方法, 即所有的Lifecycle bean都已显式接收到了stop信号 , 关闭的容器可以通过start()方法重启
ContextClosedEvent 当容器关闭时发布,即调用close方法, 关闭意味着所有的单例bean都已被销毁.关闭的容器不能被重启或refresh
RequestHandledEvent 这只在使用spring的DispatcherServlet时有效,当一个请求被处理完成时发布

框架篇 - 图8
所谓的循环依赖是指,A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。或者是 A 依赖 B,B 依赖 C,C 又依赖 A。它们之间的依赖关系如下:
所谓的循环依赖是指,A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。或者是 A 依赖 B,B 依赖 C,C 又依赖 A。它们之间的依赖关系如下:

AOP

AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码降低模块间的耦合度,并有利于未来的可拓展性和可维护性

Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:
框架篇 - 图9
当然你也可以使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。Spring 提供了 AspectJ 的支持,但只用到的AspectJ的切点解析和匹配。
使用 AOP 之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。
image.png

image.png
Advisor封装了Advise(around、before、after)和pointcut,精度可以到达方法。
AOP的使用:https://blog.csdn.net/qq_33369905/article/details/105828920

BeanFactory 和ApplicationContext区别

BeanFactory是Spring中的顶层接口,ApplicationContext是下层的接口。

public interface BeanFactory {...}

1、国际化
BeanFactory是不支持国际化功能的,因为BeanFactory没有扩展Spring中MessageResource接口。相反,由于ApplicationContext扩展了MessageResource接口,因而具有消息处理的能力(i18N)

2、强大的事件机制(Event)
基本上牵涉到事件(Event)方面的设计,就离不开观察者模式,
ApplicationContext的事件机制主要通过ApplicationEvent和ApplicationListener这两个接口来提供的,和java swing中的事件机制一样。即当ApplicationContext中发布一个事件的时,所有扩展了ApplicationListener的Bean都将会接受到这个事件,并进行相应的处理。
3、底层资源的访问
ApplicationContext扩展了ResourceLoader(资源加载器)接口,从而可以用来加载多个Resource,而BeanFactory是没有扩展ResourceLoader
4、对Web应用的支持
与BeanFactory通常以编程的方式被创建不同的是,ApplicationContext能以声明的方式创建,如使用ContextLoader。当然你也可以使用ApplicationContext的实现之一来以编程的方式创建ApplicationContext实例 。
5、延迟加载
1).BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。
2).BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册
可以看到,ApplicationContext继承了BeanFactory,BeanFactory是Spring中比较原始的Factory,它不支持AOP、Web等Spring插件,而ApplicationContext不仅包含了BeanFactory的所有功能,还支持Spring的各种插件,还以一种面向框架的方式工作以及对上下文进行分层和实现继承。
BeanFactory是Spring框架的基础设施,面向Spring本身;而ApplicationContext面向使用Spring的开发者,相比BeanFactory提供了更多面向实际应用的功能,几乎所有场合都可以直接使用ApplicationContext而不是底层的BeanFactory

SpringBoot

filter,interceptor,controllerAdvice,aspect,controller执行顺序

1、filter,这是java的过滤器,和框架无关的,是所有过滤组件中最外层的,从粒度来说是最大的。
配置方式,有直接实现Filter+@component,@Bean+@configuration(第三方的filter)
2、interceptor,spring框架的拦截器
配置方式,@configuration+继承WebMvcConfigurationSupport类添加过滤器。
3、aspect,可以自定义要切入的类甚至再细的方法,粒度最小。加个注解用效果更佳。
4、controllerAdvice,是controller的增强,和ExceptionHandler一起用来做全局异常。
总结:
filter:和框架无关,可以控制最初的http请求,但是更细一点的类和方法控制不了。
interceptor:可以控制请求的控制器和方法,但控制不了请求方法里的参数。
aspect : 可以自定义切入的点,有方法的参数,但是拿不到http请求,可以通过其他方式如RequestContextHolder获得。
框架篇 - 图12