Spring相关源码解读

1.ApplicationContext refresh的流程

spring调用refresh()方法来初始化容器

(1)prepareRefresh

这一步是为后续步骤做准备工作

创建和准备了 Environment 对象,Environment存储一些键值对
Environment 作用:
(1)为后续 @Value ,值注入时提供键值

(2)obtainFreshBeanFactory

这一步是获取(或创建) BeanFactory

(1)BeanFactory作用:
负责bean的创建、依赖注入和初始化
(2)BeanDefinition的作用:
作为bean的设计蓝图,规定了bean的特征,如单例多例、依赖关系、初始销毁方法等。BeanDefinition的来源多种多样,可以
通过xml获得、通过配置类获得、通过组件扫描获得,也可以是编程添加

(3)prepareBeanFactory

完善BeanFactory

StandardBeanExpressionResolver:用来解析EL表达式 #{}
ResourceEditorRegistrar:会注释类型解释器,并应用ApplicationContext提供的 Environment完成${}解析
registerResolvableDependency:注册特殊的bean 指 beanFactory以及ApplicationContext
ApplicationContextAwareProcessor:解析Aware接口

(4)postprocessBeanFactory

这一步是空实现,留给子类扩展

一般 Web 环境的ApplicationContext都要利用它注册新的Scope,完善Web下的BeanFactory
体现了模板方法设计模式

(5)invokeBeanFactoryPostProcessors

BeanFactory的后处理器,充当BeanFactory的拓展点,可以用来补充或修改BeanDefinition

例如:
ConfigurationClassPostProcessor:用来解析@Configuration @Bean @Import @PropertySource
PropertySourcesPlaceHolderConfigurer:用来替换BeanDefinition中的${}

(6)registerBeanPostProcessors

bean的后处理器,可以充当bean的扩展点,可以工作在bean的实例化、依赖注入、初始化阶段

(7)initMessageSource

实现国际化
从容器中找一个名为messageSource的bean,如果没有,则提供空的MessageSource实现

(8)initApplicationEventMulticaster

事件广播器

用来发布事件给监听器
从容器中找一个名为applicationEventMulticaster的bean作为事件广播器,如果没有,也会新建默认的事件广播器
可以调用ApplicationContext.publishEvent(事件对象)来发布事件

(9)onRefresh

空实现,留给子类扩展

springBoot中的子类可以在这里准备WebServer,即内嵌web容器
体现了模板方法设计模式

(10)registerListeners

事件监听器

用来接收事件
一部分监听器是事先编程添加的、另一部分监听器来自容器中的bean、还有一部分来自于@EventListener的解析
实现ApplicationListtener接口,重写其中的onApplicationEvent(E e)方法即可

(11)finishBeanFactoryInitialization

conversionService:用来类型转换的,作为对PropertyEditor的补充
embeddedValueResolvers:内迁至解析器用来解析@Value中的${},借用的是Environment的功能
singletonObjects:初始化所有非延迟单例对象,缓存所有的单例对象

(12)finishRefresh

lifecycleProcessor:生命周期处理器,控制容器中需要生命周期管理的bean
容器中有名称为lifecycleProcessor的bean就使用,否则创建默认的生命周期处理器

调用context的start,即可触发所有实现LifeCycle接口bean的start
调用context的stop,即可触发所有实现LifeCycle接口bean的stop

总结

2.spring bean 的生命周期

(1)处理名称,检查缓存

(1)先把别名解析为实际名称,再进行后续处理
(2)若要获取 FactoryBean 本身,需要使用 &名称 获取

缓存中查找对象,缓存中有就直接用,没有就创建
(3)singletonObjects是一级缓存,放单例成品对象。找对象先从一级缓存开始找
(4)singletonFactories是三级缓存,放单例工厂。可以解决循环依赖
(5)earlysingletonObjects是二级缓存,放单例工厂的产品,可称为提前单例对象。解决需要创建代理对象时产生的依赖

(2)检查父工厂

如果容器中配置了父容器,如果缓存中没有找到对象,就从父容器中找,如果父容器中找到就直接使用,否则就创建。

父子容器的bean名称可以重复
优先找子容器的bean,找到了直接返回,找不到继续到父容器中找

(3)检查 DependsOn

DependsOn 用在非显式依赖的 bean 的创建顺序控制
例如:A DependsOn B,那么就先创建B再创建A

(4)按Scope创建bean

singleton Scope:表示从单例池范围内获取bean,如果没有,则创建并放入单例池
prototype Scope:表示从不缓存bean,每次都创建新的
request Scope:表示从request对象范围内获取bean,如果没有,则创建并放入request

(5)创建bean

(1)创建阶段:
AutowiredAnnotationBeanPostProcessor选择构造:优先选择带@Autowired注解的构造;若有唯一的带参构造,也会入选
采用默认构造:如果上面的后处理器和BeanDefiniation都没找到构造,次啊用默认构造,即使是私有的

(2)依赖注入:
AutowiredAnnotationBeanPostProcessor(注解匹配):识别@Autowired及@Value标注的成员,封装为InjectionMetadata进行依赖注入
CommonAnnotationBeanPostProcessor(注解匹配):识别@Resource标注的成员,封装为InjectionMetadata进行依赖注入
AUTOWIRE_BY_NAME(根据名字匹配):根据成员名字找bean对象,修改mbd的propertyValues,不会考虑简单类型的成员
AUTOWIRE_BY_TYPE(根据类型匹配):根据成员类型执行resolveDependency找到依赖注入的值,修改mbd的propertyValues
applyPropertyValues(精确指定):根据mbd的propertyValues进行依赖注入
优先级最高的是精确指定,下来是根据名称/类型匹配,最后才是注解匹配

(3)初始化:
处理Aware接口:进行初始化,优先级最高
      @PostConstruct:通过实现后处理器实现功能
      实现InitializingBean接口:通过接口回调初始化执行
      initMethod:根据 BeanDefinition 得到的初始化方法执行初始化
创建aop代理:通过实现后处理器实现功能,优先级最低

(4)注册可销毁bean:
判断是否为可销毁bean的依据:
  如果实现了DisposableBean接口或AutoCloseable接口,则为可销毁bean
  如果自定义了destroyMethod,则为可销毁bean
  如果采用了@Bean没有指定destroyMethod,则采用自动推断的方式获取销毁方法名(close,shutdown)
  如果有@PreDestroy标注的方法
存储位置:
  singleton Scope的可销毁bean会存储于beanFactory的成员中
  自定义的scope的可销毁bean会存储于对应的域对象中
  prototype Scope不会存储,需要自己找到此对象销毁
  存储时都会封装为DisposableBeanAdapter类型对销毁方法的调用进行适配

(6)类型转换

如果getBean的requiredType参数与实际得到的对象类型不同,会尝试进行类型转换

(7)销毁bean

singleton bean:的销毁在ApplicationContext.close时,此时会找到所有DisposableBean的名字,注意销毁
自定义 scope bean 的销毁在作用域对象生命周期结束时
prototype bean的销毁可以通过自己动手调用AutowireCapableBeanFactory.destroyBean方法执行销毁

总结

3.spring事务失效的几种场景以及原因

(1)检查异常

语法上有强制要求,需要 throws或者try catch的异常

原因:spring默认只会回滚非检查异常,spring不会对检查异常进行回滚

解决:在处理此业务的类上面加 @Transactional(rollbackFor = Exception.class)这个注解

(2)错误try-catch

业务方法内自己加try-catch异常导致事务不能正确回滚

原因:事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法知悉

解决:(1)需要将异常抛出去,(2)调用 TransactionStatus.setRollbackOnly()方法通知回滚事务

(3)切面顺序

aop切面顺序导致事务不能正确回滚

原因:事务切面优先级最低,但如果自定义的切面的优先级和他一样,则还是自定义切面在内层,这时若自定义切面没有正确抛出
异常,则事务切面不能接收到异常,就不能回滚

解决:(1)需要将异常抛出去(推荐)   (2)调用 TransactionStatus.setRollbackOnly()方法通知回滚事务
	 (3)@Order(Ordered.LOWEST_PRECEDENCE - 1)

(4)非public方法

原因:spring为方法创建代理、添加事务通知、前提条件都是该方法是public的

解决:@Transactional 注解必须加在public方法上,不能加在其他方法上,必须加public修饰符

(5)父子容器

原因:子容器的扫描范围过大,把未加事务配置的service扫描进来

解决:(1)各扫描各的,不要图简便     (2)不要用父子容器,把所有的bean放在同一容器

(6)本类方法调用

调用本类方法导致传播行为失效

原因:本类方法调用不经过代理,因此无法增强

解决:(1)依赖注入自己(代理)来调用    (2)通过AopContext拿到代理对象,来调用

(7)原子性失效

@Transactional没有保证原子行为

原因:事务的原子性仅涵盖 insert  uodate  delete  select..for update 语句,select方法并不阻塞

(8)锁失效

@Transactional方法导致的synchronized失效

原因:synchronized保证的仅是目标方法的原子性,环绕目标方法的还有commit等操作,它们并未处在synchronized块内

解决:(1)synchronized范围应扩大至代理方法调用   (2)使用 select..for update 替换 select(推荐使用)

4.springMVC执行流程

(1)初始化阶段

(1)在Web容器第一次用到DispatcherServlet的时候,会创建其对象并执行init方法
(2)init方法内会创建spring web 容器,并调用容器的refresh方法
(3)refresh过程中会创建并初始化springMVC中的重要组件
(4)容器初始化后,会将上一步初始化好的重要组件,赋值给DispatcherServlet的成员变量,留待后用

(2)匹配阶段

(1)用户发送的请求同一到达前端控制器DispatcherServlet
(2)DispatcherServlet遍历所有HandlerMapping,找到与路径匹配的处理器
(3)将HandlerMethod连同匹配到的拦截器,生成调用链对像HandlerExecutionChain返回
(4)遍历HandlerAdapter处理器适配器,找到能处理HandlerMethod的适配器对象,开始调用

(3)执行阶段

(1)执行拦截器preHandle
(2)由HandlerAdapter调用HandlerMethod,调用前处理不同类型的参数,调用后处理不同类型的返回值
(3)如果第二步没有异常:
     返回ModelAndView
     执行拦截器postHandle
     解析试图,得到View对象,进行视图渲染
(4)如果第二步有异常,进入HandlerExceptionResolver异常处理流程
(5)最终都会执行拦截器的afterCompletion方法
(6)如果控制器方法标注了@ResponseBody注解,则在第2步就会生成json结果,并标记ModelAndView已处理,这样就不会执行
第3步的视图渲染

第二步没有异常

第二步有异常

5.一些注解

(1)@Configuration

(1)配置类相当于一个工厂,标注@Bean注解的方法相当于工厂方法
(2)@Bean不支持方法重载,如果有多个重载方法,仅有一个能入选为工厂方法
(3)@Configuration默认会为标注的类生成代理,其目的是保证@Bean方法相互调用时,仍然能保证其单例特性
(4)@Configuration中如果含有bean工厂后处理器,则实例工厂方法会导致配置类提前创建,造成依赖注入失败。
解决:改用静态工厂方法

(2)@Import

(1)引入单个bean:@Import(Bean1.class)
(2)引入一个配置类:@Import(OtherConfig.class)
(3)引入多个配置类,通过 Selector 选择器
(4)通过beanDefinition注册器

(3)@SpringBootApplication

(1)@SpringBootConfiguration:表示当前类是一个配置类
(2)@ComponentScan:扫描
(3)@EnableAutoConfiguration:
@AutoConfigurationPackage:所标注类的包名会被记下来,放到容器中
@Import(AutoConfigurationImportSelector .class):分离主配置和从属配置,避免强耦合;执行优先级低,先保证主配置,再解析从属配置

6.spring中有哪些设计模式

(1)单例模式

(1)singleton bean 并非实现了单例模式,它只能保证每个容器内,相同的id的bean单实例

(2)Builder模式

(1)比较灵活的构建产品对象
(2)在不执行最后build方法前,产品对象都不可用
(3)构建过程采用链式调用

(3)工厂方法模式

让接口和实现相分离,降低耦合

如:ApplicationContext 和 BeanFactory中的getBean

(4)Adapter适配器模式

把一套接口转换为另一套调用者期望的接口

(5)组合模式

把分散的调用集中起来,统一调用入口

(6)装饰器模式

对一个对象动态的增加职责和功能,避免子类继承父类所有的方法

(7)Proxy 代理模式

控制目标的访问

(8)责任链模式

(9)观察者模式

用来解耦合

(10)策略模式

(11)模板方法设计模式

7.循环依赖

(1)创建代理

@Aspect:标注的类称为切面类
@Around @Before @After :标注的方法称为切面方法
@Around("execution(* car())") : execution(* car()):切入点表达式

(2)缓存

(1)一级缓存

作用:限制bean在beanFactory中只存一份,即实现 singleton scope

问题:解决不了set循环依赖


(2)二级缓存

作用:解决set循环依赖

问题:不能解决set循环依赖中有代理的情况


(3)三级缓存

作用:解决set循环依赖中代理创建过晚的问题

(3)构造循环依赖

三级缓存不能解决构造循环依赖

解决:(1)用 @Lazy 注解(加在方法的参数前边),使用B的代理对象
	 (2)用 ObjectFactory ,使用B的工厂对象
	 (3)用 Provider,与ObjectFactory作用一样
	 (4)用 @Scope 注解(加在类上面)



(4)总结

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cw旧巷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值