轻量级框架,基本版本大约2M
实现IOC和DI,通过IOC容器实现Bean的生命周期的管理,通过DI实现依赖注入,实现对象依赖的松耦合
实现AOP,面相切面
基于spring的springmvc和springboot等轻量级框架
通过AOP实现事务的统一管理
required:默认,如果存在事务则加入,不存在则新建
require_new:不管是否存新建
nested:如果存在当前事务则嵌套,不存在则新建
supports:支持当前事务,不存在则以非事务方式执行
not_supported:非事务执行,如果存在当前事务则挂起
mandatory:强制事务执行,不存在抛异常
never:强制非事务执行,存在抛异常
创建前:通过注解或者配置类等加载bean,程序启动后,将bean对象转换成一个BeanDefination对象,对它进行解析和加载
创建实例:反射创建Bean实例,并且扫描和解析Bean声明的一些属性
依赖注入:根据BeanDedinition的信息进行依赖注入,populateBean完成属性的注入。
容器缓存:调用Aware接口的相关方法,完成对beanName、beanClassLoader、beanFactory对象的属性设置;调用前置处理方法、initMethod、后置处理方法。
销毁:spring应用上下文关闭时,所有的bean都会被销毁。如果存在实现了DisposableBean接口或配置了destory-method
属性,会被调用
单例:spring容器只会创建一个Bean的实例,在整个程序中共享。每次获取该bean时,都会返回同一个实例对象。默认情况下,是单例的。
多例:scope="prototype"
,每次请求获取Bean都会创建一个新的实例,每个实例都是独立的。
基于spring框架的web应用里,增加了一个会话维度控制bean生命周期
request:每次请求创建一个新的bean
session:同一个session共享一个bean
globalSession:全局session共享一个bean
多例bean每次都会创建新实例,因此不存在线程安全问题
单例bean是共享一个实例,可能存在线程安全问题。单例bean又分为有状态bean和无状态bean。
多线程中只对bean的成员变量查询不改变的称为无状态bean,不存在线程安全问题
多线程中对bean成员变量更新操作称为有状态bean,存在线程安全问题
解决:
将作用域右单例改为多例
定义threadLocal成员变量,将需要的可变成员变量保存到其中,相当于为每个线程提供了一个独立的变量副本,每个线程只需要操作自己的副本
XML声明的bean定义
@Import
,导入配置类或普通的bean
@Configuration
,声明配置类,使用@Bean
实现bean的定义
@CompontScan
,声名@Controller、@Service等的注解的类
使用FactoryBean
,动态构建一个 Bean 实例,OpenFeign动态代理实例就是使用FactoryBean 实现的
实现ImportBeanDefinitionRegistrar
接口,动态注入 Bean 实例。在SpringBoot启动注解有用到。
实现ImportSelector
接口,动态批量注入配置类或者 Bean 对象,在 SpringBoot 自动装配机制里用到。
控制反转,就是把对对象的管理交给容器,需要使用对象实例,直接从IOC容器中获取,降低对象与对象之间耦合性。
有很多方式去定义bean,XML文件、@Service、@Configution,@Componet等,在spring启动的时候,回去解析bean然后保存到IOC容器中。
IOC初始化,通过各种方式解析和加载后生成BeanDefinition实体,实体包含bean基本属性,然后注册到IOC
bean初始化及依赖注入,通过反射对没有设置lazy-init的单例bean进行初始化,完成依赖注入
通过@AutoWired或则getBean从容器获取bean并使用,对设置lazy-init的单例bean的实例化是在每次获取bean的时候,调用bean的初始化方法完成实例化的,容器不会去管理这些bean
依赖注入,如果Bean之间存在依赖关系,那么IOC需要自动实现依赖对象的实例注入
接口注入、setter注入、构造器注入、@Autowired等注解
BeanFactory是所有spring bean的顶级接口,为spring容器定义一套规范,并提供getBean这样的方法从容器中获取指定的Bean实例。在产生bean的同时,提供了解决bean之间依赖注入的能力。
FactoryBean是一个工厂bean,是一个接口,主要是动态生成一个类型的bean实例,有一个getObject方法就是用来实现动态构建Bean的过程
创建代理对象:调用getBean(),创建实例后,根据AOP的配置去匹配目标类的类名,是否满足切面规则,然后调用ProxyFactory
创建代理bean并缓存到IOC容器,选择代理策略,如果目标类实现了接口默认选择JDK代理,否则使用bglib代理。
拦截目标对象:AopProxy拦截,调用invocationHandler的invoke(),触发MethodInvocation的proceed(),按顺序执行符合所有AOP拦截规则的拦截器链
调用代理对象:反射调用Advice对象,执行织入代码
调用目标对象:执行MethodInterceptor 的 invoke(), 调用目标对象
JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
cglib代理:CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并在拦截方法相应地方织入横切逻辑。
@Resource :JDK提供的注解,可以根据name和type匹配,默认是name
@Autowired :required 属性默认值是 true,表示强制要求 bean 实例的注入;
根据type匹配,如果需要支持name就要配合@Primary或者@Qualifier实现
判断bean是否满足条件,再装载IOC中
可以实现Condition接口并重写matches方法
如果在同一个xml中相同id的bean,启动时会报错,因为id标识bean的唯一标识符,是在对xml文件解析转化为beanDefinition的阶段
不同的xml文件里,可以存在id相同的,IOC加载bean的时候会覆盖
如果使用@Configuration,声明多个名称相同的bean,只会注册第一个实例
如果使用@Autowired,根据类型,启动报错找不到
如果使用@Resource,根据名称,报错类型不匹配
循环依赖是两个或者多个bean相互持有对方的引用造成的死循环问题
spring设计了三级缓存解决。当调用getBean方法的时候,spring先从一级缓存找bean,如果一级缓存没有就去二级缓存找,如果都没有,意味着bean没有实例化,然后spring容器会实例化bean,将bean放入二级缓存,同时加上标记是否存在循环依赖,如果存在就将bean放入二级缓存,等待下一次轮询赋值,也就是解析@Autowired注解,等赋值完成后,将bean存入一级缓存。
三级缓存什么作用?
三级缓存是用来存储代理bean,当调用getBean时,发现目标bean需要通过代理工厂创建,就会将创建好的实例保存到三级缓存,最终赋值完成的bean同步到一级缓存
spring哪些情况下,不能解决循环依赖?
多例bean通过setter注入,需要改成单例
构造器注入的bean,可以使用@Lazy
单例的代理bean通过setter注入,可以使用@Lazy
@DependsOn注解的,找到循环的地方,迫使不循环
spring没有提供事务,只是提供了对数据库事务管理的封装,通过声明式的事务配置,本质上就是数据库蒙面的事务
分布式事务,是解决多个数据库的事务操作的数据一致性问题
使用上没有关联,可以使用Seata
采用了MVC架构,model、view、controller分离
文件处理器:用于处理上传请求
当前环境处理器:视图解析、用到国际化资源或主题的时候
主题处理器:解析主题,解析仰视、图片和形成的显示效果的集合
处理器映射器
:每个请求都需要一个Handler处理,HandlerMapping就是找到请求相应的处理器
处理器适配器
:让固定的servlet处理方法调用灵活的Handler进行处理
异常处理器:处理其他组件产生的异常情况
视图名称翻译器:从请求中获取ViewName,有的Handler处理完后没有设置view也没viewName,就要从请求获取
页面渲染处理器
:将string类型的视图名和Locale解析为view类型的视图
参数传递管理器:处理完post请求后重定向到另一个get请求,这个get请求可以返回页面渲染需要的信息
HandlerMapping 回到调用 HandlerAdapter
HandlerAdapter 会返回 ModelAndView
ModelAndView 根据用户传入参数得到 ViewResolvers
ViewResolvers 会将用户传入的参数封装为 View,交给引擎进行渲染。
发起请求,被servlet拦截转发给mvc框架
DispatchSerlvet核心控制器,接收到请求并转发给HandlerMapping
HandlerMapping解析请求,根据请求信息和配置信息找到匹配的Controller类
请求参数传递给Controller里的方法
执行完方法后,返回一个ModelAndView,包括视图名称和模型数据
视图解析器根据名称找到视图,渲染后返回给客户端
过滤器在servlet接收到请求之后,但在servlet被调用之前运行
拦截器在servlet调用之后,但在响应被发送到客户端之前运行
过滤器在web.xml中配置,拦截器在spring配置文件中配置或者使用注解
过滤器依赖于servlet,拦截器不依赖servlet
过滤器只能对request和response操作,拦截器可以对request、response、handler、modelAndView、excepion操作