Spring相关梳理
Spring
了解 Spring
1、Spring 通过 IoC 容器 把对象以
bean的形式进行管 ,提供了访问 IoC 容器的根接口BeanFactory。早期也被称作为万能胶不仅管理我们 new 的对象,还可以管理其他框架以及组件,同时也降低了配置的离散度2、另外它也提供了很多扩展点
- 像
BeanDefinitionReader接口定义了约束规范,不光支持Xml、注解等形式,还可以扩展其他的形式- 像
PostProccessor后置处理器也增强了很多扩展功能
DI依赖注入 就是通过子类BeanFactoryPostProceessor来扩展的,对依赖注入的不同操作进行相应的处理AOP面向切面 也是通过子类BeanPostProceessor的后置处理中扩展,另外AOP还依赖了动态代理Jdk/Cglib3、
SpringMVC是Spring基于Servlet的 web 端轻量级框架,在父子容器的装配时需要注意:父容器不能直接访问子容器注入的对象,但是子容器可以访问父容器注入的对象。4、
SpringBoot是基于Spring注解驱动发展 以及 约定优于配置理念下的产物,SpringCloud又是基于SpringBoot进行的再次扩展。5、Spring 不光是个框架和容器,他也是一种生态,自身更是这个生态的基石。
Bean的加载过程

扩展点 BeanDefinitionReader 为何使用的是接口而不是抽象类
接口自上而下;抽象类自下而上。接口更注重用设计来提升扩展,只管设计方案不需要考虑谁来实现;而抽象类着重点在于重构,在已有的子类中来抽取共性。语法上的区别:
- 接口被实现,抽象类被继承;
- 接口只能声明方法不能实现,抽象类可以声明也可以实现;
- 接口中的变量只能是公共的静态变量,抽象类可以是普通变量;
自定义增强器
//自定义增强器
public class MyBFPP implements BeanFactoryPostProccessor{
@Override
public void postProccessBeanFactory(ConfigurableListableBeanFactory beanFactory){
BeanDefinition person = beanFactory.getBeanDefinition("person");
person.set(); // 修改 BeanDefinition
}
}
<!-- 注册到容器 -->
<bean class="com.xxx.Spring.MyBFPP"/>
BeanFactory 与 FactoryBean
-
BeanFactory是顶层接口。提供了 IoC容器 最基本的方式,给具体的 IoC 容器实现 提供了规范。并且也是访问 IOC 容器的根接口,提供方法支持外部程序对这些 bean 的访。 -
FactoryBean也是接口。 为 IoC容器中 Bean的实现提供了更加灵活的方式,在 IoC 容器的基础上给Bean的实现加上了一个简单的工厂模式和装饰模式。有三个方法isSingleton();getObjectType();getObject() -
BeanFactory创建的对象必须遵循完整的 bean 的生命周期,而FactoryBean没有标准的流程。BeanFactory如果比作是流水线,那FactoryBean就是私人订制。
Bean 生命周期

循环依赖
// 相互依赖问题
public class A{ private B b; }
public class B{ private A a; }

//一级缓存 存的是Object:实例话初始化都已完成的对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//二级缓存 存的是Object:实例话完成,初始化未完成的对象
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//三级缓存 存的是函数式接口:lambda表达式,防止容器同名代理对象被覆盖原始对象
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//执行顺序:从一级、二级、三级层层查找。
ObjectFactory<?>,函数式接口,有且仅有一个方法并且当作参数传入声明此类型的方法,可以接收 lambda 表达式,在执行的时候不会执行 lambda 表达式,而在调用 getObject 方法的时候才会去调用 lambda 处理的逻辑
一个 Map 可否解决
不能,如果只有一个Map,初始化完成与初始化未完成的对象都要放入一个Map,而未完成初始化的对象不能暴露给外部使用,所以必须要分开存储。
两个 Map 可否解决
能,但是有前提条件:不使用 AOP 的時候,或者说在BeanPostProccessor的后置处理方法中没有创建代理对象的时候,两个 Map 可以解决循环依赖。否则会报错:Bean的版本问题。
三级缓存为何可以解决
1、创建代理对象的时候需要有原始对象,同一个容器不能出现同名的两个不同对象。如果需要代理对象,那么代理对象创建完成之后就会覆盖掉原始对象。
2、对外暴露的时候需要准确的对象,要么原始对象要么代理对象。但是代理对象的创建是在
BeanPostProccessor的后置处理方法中,解决循环依赖问题的时候还没有执行到那一步,因此需要lambda表达式,类似于一种回调机制,就可以准确的暴露对象了。3、什么时候需要暴露于,程序没办法确定,所以需要通过
lambda的方式,在确定对外暴露的时候才去确定
Spring MVC
工作原理图

配置拦截器
两种方式
1、实现
HandlerInterceptor接口 或者 继承HandlerInterceptorAdapter类,配置拦截器的 Bean2、实现
Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类
Spring Boot
约定优于配置理念下的产物
在 @SpringBootApplication 注解下有三个重要的注解
@EnableAutoConfiguration,用于自动装配@SpringBootConfiguration,配置类,内部使用的就是@Configuration@ComponentScan,扫描路径加载IoC容器
自动装配
自动装配的过程
@EnableAutoConfiguration引入了@Import(AutoConfigurationImportSelector.class)注解,而AutoConfigurationImportSelector实现了ImportSelector的子接口DeferredImportSelector,然后通过selectImport配合SPI 机制,来实现自动装配。
SPI 机制
通过
SpringFactoriesLoader扫描classpath:META-INF/spring.factories中所有的文件。在SpringBoot中分为两种:三方包、官方包
- 三方包命名规则
mybatis-spring-boot-starter,在自己引入的包下的META_INF/spring.factories中配置,扫描到可以进行自动装载。- 官方包命名规则
spring-boot-starter-data-redis,在spring-boot-antoconfiguration下的META_INF/spring.factories中配置,里面有一堆定义好的配置信息。通过@ConditionelOnClass注解进行条件控制,只有符合条件的配置信息才会进行自动装载。
Starter 组件
Starter 组件是 Spring Boot 提供 开箱即用 的组件
本质上就是通过 maven 编译安装的 JAR 包,依赖于自动装配 遵循 SPI 机制 来实现的
开箱即用。
Actuator
就是用于监控的组件,通过
management-endpoints去设置一些需要监控的内容。为了安全考虑,默认只开放info、health。除此之外有个重要的监控
metrics用于监控运行指标的
- JVM(垃圾回收,内存)
- 系统(运行时间,平均负载,处理器信息)
- 线程池 信息
- tomcat 会话信息
- ...
可以通过
Prometheus和Grafana等工具,进行图表展示。
Spring Boot CLI
是个命令行工具
用于快速开发 Spring 应用
通过
Groovy脚本运行
本文来自博客园,作者:柒徳咙咚呛,转载请注明原文链接:https://www.cnblogs.com/JustDoIt-1221/p/16242816.html

浙公网安备 33010602011771号