框架篇


spring的Bean的生命周期

阶段1: 处理名称,检查缓存

  1. 先把别名解析为实际名称,再进行后续处理
  2. 若要FactoryBean本身,需要使用&名称获取
  3. singletonObjects是一级缓存,放单例成品对象
  4. singletonFactories是三级缓存,放单例工厂
  5. earlySingletonObjects是二级缓存,放单例工厂的产品,可称为提前单例对象

阶段2:处理父子容器

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

阶段3:dependsOn

1.dependsOn用在非显式依赖的bean的创建顺序控制

阶段4: 按Scope创建bean

  1. scope理解为从xxx范围内找这个bean更加贴切
  2. singleton scope表示从单例池范围内获取bean,如果没有,则创建并放入单例池
  3. prototype scope表示从不缓存bean,每次都创建新的
  4. request scope 表示从request对象范围内获取bean,如果没有,则创建并放入request

阶段5-1:创建bean实例

  1. AutowiredAnnotationBeanPostProcessor选择构造

    优先选择带@Autowired注解的构造
    若有唯一的带参构造,也会入选

2 . 采用默认构造

如果上面的后处理器和BeanDefiniation都没找到构造,采用默认构造,即使是私有的

阶段5-2:依赖注入

  1. AutowiredAnnotationBeanPostProcessor(注解匹配)

    识别@Autowired及@Value标注的成员,封装为InjectionMetadata进行依赖注入

2.CommonAnnotationBeanPostProcessor(注解匹配)

识别@Resource标注的成员,封装为InjectionMetadata进行依赖注入

3.AUTOWIRE_BY_NAME(根据名字匹配)

根据成员名字找bean对象,修改mbd的propertyValues,不会考虑简单类型的成员

4.AUTOWIRE_BY_TYPE(根据类型匹配)

根据成员类型执行resolveDependency找到依赖注入的值,修改mod的propertyValues

5.applyPropertyValues(即xml中<property name ref|value/>)(精确指定)

根据mbd的propertyValues进行依赖注入

小插曲,问多种配置bean,那种优先级高?

  1. 优先级最高的:精确指定注入bean的名称<property name ="bean3" ref ="bean2"/>
  2. 优先级次之的:通过AUTOWIRE_BY_NAME匹配
  3. 优先级最低的:@Autowired匹配

阶段5-3: 初始化

1.内置Aware接口的装配

包括BeanNameAware,BeanFactoryAware等

2.内置Aware接口的装配

由ApplicationContextAwareProcessor解析,执行时机在postProcessBeforeInitialzation

3.@PostConstruct

由CommonAnnotationBeanPostProcessor解析,执行时机在postProcessBeforeInitialization

4.InitializingBean

通过接口回调执行初始化

5.initMethod(即或@Bean(initMethod))

根据BeanDefinition得到的初始化方法执行初始化

6.创建aop代理

由AnnotationAwareAspectJAutoProxyCreator创建,执行时机在postProcessAfterInitialization

它们的执行顺序

1.Aware接口->@PostConstruct->InitializingBean->initMethod

阶段5-4:注册可销毁bean

判断依据

  1. 如果实现了DisposableBean或AutoCloseable接口,则为可销毁bean
  2. 如果自定义了destroyMethod,则为可销毁bean
  3. 如果采用@Bean没有指定destroyMethod,则采用自动推断方式获取销毁方法名(close,shutdown)
  4. 如果有@PreDestroy标注的方法

存储位置

  1. singleton scope的可销毁bean会存储beanFactory的成员当中
  2. 自定义scope的可销毁bean会存储于对应的域对象当中
  3. prototype scope不会存储,需要自己找到此对象销毁

存储时都会封装为DisposableBeanAdapter类型对销毁方法的调用进行适配

阶段6:类型转换

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

阶段7:销毁bean

  1. singleton bean的销毁在ApplicationContext.close时,此时会找到所有DisposableBean的名字,逐一销毁
  2. 自定义scope bean的销毁在作用域对象生命周期结束时
  3. prototype bean 的销毁可以通过自己手动调用AutowireCapableBeanFactory.destroyBean方法执行销毁
  4. 同一bean中不同形式销毁方法的调用次序

    优先后处理器销毁,即@PreDestroy
    其次DisposableBean接口销毁
    最后destroyMethod销毁(包括自定义名称,推断名称,AutoCloseable接口多选一)

Spring事务失效的几种场景及原因

抛出检查异常导致事务不能正确回滚

原因:Spring默认只会回滚非检查异常
解法:配置rollbackFor属性

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

原因:事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理异常,事务通知无法知悉
解法1:异常原样抛出
解法2:手动设置TransactionStatus.setRollbackOnly()

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

原因:事务顺序优先级最低,但如果自定义的切面优先级和他一样,则还是自定义切面在内层,这时若自定义切面没有正确抛出异常…
解法:同情况2

非public方法导致的事务失效

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

父子容器导致的事务失效

原因:子容器扫描范围过大,把未加事务配置的service扫描进来
解法1:各扫描各的,不要图简便
解法2:不要用父子容器,所有bean放在同一容器

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

原因:本类方法调用不经过代理,因此无法增强
解法1:依赖注入自己(代理)来调用
解法2:通过AopContext拿到代理对象,来调用
解法3:通过CTW,LTW实现功能增强

@Transactional没有保证原子行为

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

@Transactional方法导致的synchronized失效

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

SpringMVC执行流程

初始化阶段:

  1. 在Web容器第一次用到DispatcherServlet的时候,会创建其对象并执行init方法
  2. init方法内会创建Spring Web容器,并调用容器refresh方法
  3. refresh过程中会创建并初始化SpringMVC中的重要组件,例如MultipartResolver,HandlderMapping,HandlerAdapter,HandlerExceptionResolver,ViewResolver等
  4. 容器初始化后,会将上一步初始化好的重要组件,赋值给DispatcherServlet的成员变量,留待后用

匹配阶段:

  1. 用户发送的请求统一到达前端控制器DispatcherServlet

  2. DispatcherServlet遍历所有HandlerMapping,找到与路径匹配的处理器

  3. HandlerMapping有多个,每个HandlerMapping会返回不同的处理器对象,谁先匹配,返回谁的处理器。其中能识别@RequestMapping的优先级最高

  4. 对应@RequestMapping的处理器是HandlerMethod,它包含了控制器对象和控制器方法信息

  5. 其中路径与处理器的映射关系在HandlerMapping初始化时就会建立好

  6. 将HandlerMethod连同匹配到的拦截器,生成调用链对象HandlerExecutionChain返回

  7. 遍历HandlerAdapter处理器适配器,找到能处理HandlerMethod的适配器对象,开始调用

执行阶段:

  1. 执行拦截器preHandle

  2. 由HandlerAdapter调用HandlerMethod

  3. 调用前处理不同类型的参数

  4. 调用后处理不同类型的返回值

  5. 第2步没有异常

  6. 返回ModelAndView

  7. 执行拦截器postHandle方法

  8. 解析视图,得到View对象,进行视图渲染

  9. 第2步有异常,进入HandlerExceptionResolver异常处理流程

  10. 最后都会执行拦截器的afterCompletion方法

  11. 如果控制器方法标注了@ResponseBody注解,则在第2步,就会生成json结果,并标记ModelAndView已处理,这样就不会执行第3步的视图渲染

SpringBootApplication

  1. @SpringBootConfiguration

  2. @ComponentScan

  3. excludeFilters-用来在组件扫描时进行排除,也会排除自动配置类

  4. @EnableAutoConfiguration

  5. @AutoConfigurationPackage -用来记住扫描的起始包

  6. @Import(AutoConfigurationImportSelector.class)用来加载META-INf/spring.factories中的自动配置类

SpringBoo的启动

  1. springboot是通过main方法下的SpringApplication.run方法启动的
  2. 启动的时候他会调用refshContext方法,先刷新容器,然后根据解析注解或者解析配置文件的形式祖册bean
  3. 而它是通过启动类的SpringBootApplication注解进行开始解析的
  4. 他会根据EnableAutoConfiguration开启自动化配置
  5. 里面有个核心方法ImportSelect选择性的导入
  6. 根据loadFanctoryNames根据classpash路径以MATA-INF/spring.factorces下面以什么什么EnableAutoConfiguration开头的key去加载里面所有对应的自动化配置
  7. 他并不是把这一百二十多个自动化配置全部导入,在他每个自动化配置里面都有条件判断注解,先判断是否引入相互的jar包,再判断容器是否有bean再进行注入到bean容器

创建代理

  1. 最基本的切面是Advisor,一个Aspect切面对应一到多个Advisor

  2. 最基本的Advice是MethodInterceptor,其他Advice最终都将适配为MethodInterceptor

  3. 创建代理的方式

  4. 实现了用户自定义接口,采用jdk动态代理

  5. 没有实现用户自定义接口,采用cglib代理

  6. 设置了setProxyTargetClass(true),统一采用cglib代理

  7. 切面,切点,通知等不会被代理

  8. AnnotationAwareAspectJAutoProxyCreator调用时机:创建阶段,依赖注入阶段,初始化阶段

循环依赖

单例set方法(包括成员变量)循环依赖,Spring会利用三级缓存解决,无需额外配置

  1. 一级缓存存放成品对象
  2. 二级缓存存放发生了循环依赖时的产品对象(可能是原始bean,也可能是代理bean)
  3. 三级缓存存放工厂对象,发生循环依赖时,会调用工厂获取产品
  4. Spring期望在初始化时创建代理,但如果发生了循环依赖,会由工厂提前创建代理,后续初始化就不必重复创建代理
  5. 二级缓存的意义在于,如果提前创建了代理对象,在最后的阶段需要从二级缓存中获取此代理对象,作为最终结果

构造方法及多例循环依赖解决办法

  1. @Lazy
  2. @Scope
  3. ObjectFactroy & ObjectProvider
  4. Provider

文章作者: 小猩
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小猩 !
  目录