Java框架-Spring系列
BeanFactory和ApplicationContext的区别
- beanfactory是spring容器的访问根接口,是访问spring容器的基本调用方式。beanfactory持有着所有bean定义,容器中的bean可以是单例也可以是非单例。beanFactory同时也作为应用组件的注册器,可以集中配置应用组件
- ApplicationContext是beanFactory的拓展接口,主要目标是为应用运行所需的配置bean,并添加一些增强功能
- 通过MessageSource提供国际化支持;
- 提供事件发布订阅处理能力
- 通过ResourceLoader提供文件加载能力
- 容器的嵌套能力
Spring容器bean生命周期
spring容器负责管理创建的bean的生命周期,它存在创建初始化阶段,同样也存在着不需要使用bean是的一系列析构并将bean从容器中移除操作;
bean定义注册:会执行:BeanFactoryPostProcessor接口的实现类,对bean定义修改
实例化:
拓展点:**AwareBeanPostProcessor#postProcessBeforeInstantiation
- 方法如果返回实例对象时会短路bean的实例化、属性注入和初始化,直接跳到BeanFactoryPostProcessor的after方法
- 方法如果返回null,则正常执行
doCreateBean->createBeanInstance进行实例化
实例化的方法:
- 构造器实例化:@Component等注解都是构造器创建,@Bean也是
- 静态工厂:不需要工厂Bean实例,比如@Configuration注解的class中使用注解的静态方法**
- 实例工厂:需要先创建工厂bean,然后使用工厂bean创建实例。相对于静态工厂,实例工厂更加灵活
- 实现FactoryBean接口:本质上是一种特殊的实例工厂,与spring集成高度集成,支持延迟初始化、自动AOP代理
属性注入:
doCreateBean->populateBean- 拓展点:InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation,boolean 判断是否需要属性注入
- 拓展点:InstantiationAwareBeanPostProcessor#postProcessProperties
- 执行属性注入,比如@Autowired等复杂注入的的实现方式
初始化:
doCreateBean->initializeBean- 回调Aware接口
- BeanPostProcessor#postProcessBeforeInitialization
- @PostConstruct:实际上也是通过BeanPostProcessor实现的,不过执行顺序靠后
- InitializingBean#afterPropertiesSet
- initMethod:@Bean(initMethod=xxx)、xml指定的initMethod
- BeanPostProcessor#postProcessAfterInitialization
使用
销毁
- @PreDestory
- DisposableBean->destroy
spring的拓展点
流程图片:
ioc实现
- spring中ioc具体实现是BeanFactory,BeanFactory是spring ioc容器的核心接口。
- 主要两个核心的能力实现ioc
- 1、容器+工厂:BeanFactory持有并管理者所有的bean定义、bean对象,掌握着bean生命周期
- 2、BeanFactory提供一种bean的配置机制也就是依赖注入,让任何类型的对象都可以通过配置
- 这种灵活的ioc机制也让spring容器更加容易和其他技术集成融合和拓展。比如ApplicationContext作为BeanFactory子接口,通过MessageSource拓展国际化能力,SpringAop的集成,事件传播能力
控制反转思想
‘反转’本质是控制权归属的转移:从“开发者控制对象生命周期”反转为“容器控制对象生命周期”。
为什么叫“反转”?——好莱坞原则解释
“Don’t call us, we’ll call you.” (别找框架,框架会找你)
- 正向调用:开发者作为调用方,主动调用框架API(如J2EE的
EJBHome.create())。 - 反转调用:容器作为调用方,主动执行开发者编写的组件(如调用
@Service的方法)。
- 正向调用:开发者作为调用方,主动调用框架API(如J2EE的
依赖注入对的实现
- 主要依赖三种方式:构造器参数注入、set方法注入、反射注入
spring如何解决循环依赖
- 通过三个Map解决,singletonFactories单例对象工厂的Map、earlySingletonObjects提前实例化的单例对象的Map、singletonObjects单例对象的Map
- 假如A、B相互属性依赖
- 在初始化A之前,先将A以工厂的形式加入到三级Map;使用工厂是因为如果A被AOP代理,那么B中的依赖A就应该是代理对象,需要提前为A生成代理。
- 接着进行A的属性注入,此时发现需要一个B实例,这时候通过容器去获取B实例,发现三个Map都没有;
- 接着会先去创建B实例,到这里还是正常的流程;
- 在B的创建时,也会加入到三级Map,然后进行属性注入,这是发现需要A实例,并且在三级Map中发现有A,于是拿到A实例,并且把A移动到二级Map,B完成属性注入、初始化操作;
- B创建完成,这时候在一级Map已经有B实例,这是后回到A的属性注入,A也顺利拿到B实例,属性注入完成;
二级缓存的作用
处理循环依赖**
临时**存放需要提前暴露的bean,就是存在循环依赖的bean,提前暴露的bean是还没完成初始化的,只是new出来,尚未完成依赖注入。完成依赖注入、初始化后移动到一级缓存
三级缓存的作用
处理循环依赖中的aop代理- **
临时存放存在循环依赖并且需要aop代理的bean工厂对象。一个bean刚刚创建出来,会被包装成工厂对象**放到三级缓存,在存在循环依赖需要提前暴露这个bean时通过这个工厂对象获取到该bean的引用。- 工厂的作用:把判断是否需要创建代理和创建代理的过程包装起来,需要的时候在执行创建代理
- 好处1:创建判断是否需要创建代理和创建代理的的逻辑可以复用
- 好处2:对于有循环依赖的bean提前创建代理对象,对于没有循环依赖的bean延迟创建代理对象(延迟到
postProcessAfterInitialization)
- 如果有aop,这个工厂对象会生成aop代理对象
- 如果没有则返回bean引用
- 如果没有没有循环依赖,三级缓存在初始化完bean后直接被删除
- 工厂的作用:把判断是否需要创建代理和创建代理的过程包装起来,需要的时候在执行创建代理
- 三级缓存没有提高效率
说下springAop
- Aop理解:aop是面向对象的延补充。开发中存在横向的系统级服务关注点、业务核心关注点。业务核心关注点一般数据和行为封装成各种业务对象,同时会包含着许多横向的系统级行为,如日志。统一的行为即可优化,通过面向切面的方式将这种统一的行为进行提取, 以提高系统的模块化,这就是aop所做的事情;
- 通过通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器在Bean生命周期的最后一步来完成AOP代理
- springAop有两种实现方式:JDK动态代理、CGLIB代理
- jdk代理实际上是一种接口代理,没有实现接口的对象则无法代理
- CGLIB通过生成子类的方式进行代理,需要注意必须是非final类的对象,通过继承生成子类。
- 目标(结果):分离应用的业务逻辑与系统级服务,提高应用的模块化。
spring事务实现方式
- 1、通过编码式的事务;2、通过使用注解实现声明式事务
- 事务传播行为
- REQUIRED:默认行为。当前方法需要在事务中运行,如果已有事务则加入,没有则创建一个事务
- SUPPORTS:当前方法运行的环境若有事务,则在事务中运行;若没有事务,则不再事务中运行
- MANDATORY:当前方法必须运行在一个已有事务的环境中,否则报错
- REQUIRES_NEW:当前方法会创建一个新的事务。若已有事务,则将事务挂起,方法运行结束在继续运行。
- NOT_SUPPORTED:当前方法不需要事务。若已有事务,则将事务挂起直到该方法运行结束
- NEVER:当前的方法不应该在一个事务中运行。如果一个事务正在进行,则会抛出一个异常。
- NESTED:当前方法需要运行在一个事务中。若当前有事务,则创建一个子事务;若没事务,则创建一个新事务。子事务回滚不会导致父事务回滚
事务隔离级别
- read uncommitted、read committed、repeatable read、serializable
- 依赖于ioc、aop实现
Spring MVC 运行流程
- 请求交给DispatchServlet,在这个Servlet中做统一的流程调度处理
- 检查是否是文件上传请求,是的话预先处理文件
- DispatchServlet中,通过request匹配找到HandlerMapping方法处理器,这个处理器只是一些元数据和拦截器处理链
- 根据HandlerMapping找到HandlerAdapter,通过adapter执行接口逻辑,并获取执行结果
- 将执行结果转换成响应的视图对象
- 使用视图解析器解析视图对象并返回请求
Spring 框架中用到了哪些设计模式
- 代理模式
- 观察者模式
- 策略模式 - 骑手结算中,根据不同条件采用不同的结算方法
- 模板方法模式 - 发单流程里面,通过发单到不同配送平台,发单过程处理流程一样,只是数据流向不一样
- 工厂模式
- 单例模式: 唯一序列号生成器
springMVC原理
- springMVC主要通过核心DispatchServlet执行调度处理请求,DispatchServlet将处理工作交给了几个核心组件完成:
- 请求映射器HandlerMapping:根据url,head、请求方法、cookie等映射到相应的方法处理器;
- 处理适配器HandlerAdapter:方法处理器的执行单位,请求映射器解析到请求的处理方法后仅有请求的元数据,需要通过设配器进行统一的适配执行;
- 请求拦截器intercepter:请求拦截器,在执行方法处理器前后拦截执行,类似ServletAPI中的filter
- 逻辑视图ModelAndView:方法处理器执行后返回的模型视图,包括返回的视图类型、请求执行结果、其他请求域数据
- 视图解析器ViewResolver:HandlerAdapter执行完请求逻辑后返回一个逻辑视图,ViewResolver主要负责将逻辑视图解析成真实视图,可能是html视图、json视图等。
SpringSecurity的原理
- ss是一个认证授权的框架,执行流程上主要是通过servletApi中的filter来实现认证授权。
- ss有几个核心的组件,SecurityContextHolder,AuthenticationProvider,UserDetailsService
- 在初始化的时候根据配置,生成uri与filter责任链的映射并存储在内存中
- 当请求到达时,根据uri找到相应的filter处理链,然后执行相应的处理处理链;
- 登录请求时,请求会进入到authticationfilter,通过调用AuthenticationProvider进行登录认证,认证通过后生成响应的认证上下文context,并在放到ThreadLocal中。