• Spring相关源码解读


    1.ApplicationContext refresh的流程

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

    (1)prepareRefresh

    这一步是为后续步骤做准备工作
    
    创建和准备了 Environment 对象,Environment存储一些键值对
    Environment 作用:
    (1)为后续 @Value ,值注入时提供键值
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (2)obtainFreshBeanFactory

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

    (3)prepareBeanFactory

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

    (4)postprocessBeanFactory

    这一步是空实现,留给子类扩展
    
    一般 Web 环境的ApplicationContext都要利用它注册新的Scope,完善Web下的BeanFactory
    体现了模板方法设计模式
    
    • 1
    • 2
    • 3
    • 4

    (5)invokeBeanFactoryPostProcessors

    BeanFactory的后处理器,充当BeanFactory的拓展点,可以用来补充或修改BeanDefinition
    
    例如:
    ConfigurationClassPostProcessor:用来解析@Configuration @Bean @Import @PropertySource
    PropertySourcesPlaceHolderConfigurer:用来替换BeanDefinition中的${}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (6)registerBeanPostProcessors

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

    (7)initMessageSource

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

    (8)initApplicationEventMulticaster

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

    (9)onRefresh

    空实现,留给子类扩展
    
    springBoot中的子类可以在这里准备WebServer,即内嵌web容器
    体现了模板方法设计模式
    
    • 1
    • 2
    • 3
    • 4

    (10)registerListeners

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

    (11)finishBeanFactoryInitialization

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

    (12)finishRefresh

    lifecycleProcessor:生命周期处理器,控制容器中需要生命周期管理的bean
    容器中有名称为lifecycleProcessor的bean就使用,否则创建默认的生命周期处理器
    
    调用context的start,即可触发所有实现LifeCycle接口bean的start
    调用context的stop,即可触发所有实现LifeCycle接口bean的stop
    
    • 1
    • 2
    • 3
    • 4
    • 5

    总结

    2.spring bean 的生命周期

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

    (1)先把别名解析为实际名称,再进行后续处理
    (2)若要获取 FactoryBean 本身,需要使用 &名称 获取
    
    缓存中查找对象,缓存中有就直接用,没有就创建
    (3)singletonObjects是一级缓存,放单例成品对象。找对象先从一级缓存开始找
    (4)singletonFactories是三级缓存,放单例工厂。可以解决循环依赖
    (5)earlysingletonObjects是二级缓存,放单例工厂的产品,可称为提前单例对象。解决需要创建代理对象时产生的依赖
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (2)检查父工厂

    如果容器中配置了父容器,如果缓存中没有找到对象,就从父容器中找,如果父容器中找到就直接使用,否则就创建。
    
    父子容器的bean名称可以重复
    优先找子容器的bean,找到了直接返回,找不到继续到父容器中找
    
    • 1
    • 2
    • 3
    • 4

    (3)检查 DependsOn

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

    (4)按Scope创建bean

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

    (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类型对销毁方法的调用进行适配
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    (6)类型转换

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

    (7)销毁bean

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

    总结

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

    (1)检查异常

    语法上有强制要求,需要 throws或者try catch的异常
    
    原因:spring默认只会回滚非检查异常,spring不会对检查异常进行回滚
    
    解决:在处理此业务的类上面加 @Transactional(rollbackFor = Exception.class)这个注解
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (2)错误try-catch

    业务方法内自己加try-catch异常导致事务不能正确回滚
    
    原因:事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法知悉
    
    解决:(1)需要将异常抛出去,(2)调用 TransactionStatus.setRollbackOnly()方法通知回滚事务
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (3)切面顺序

    aop切面顺序导致事务不能正确回滚
    
    原因:事务切面优先级最低,但如果自定义的切面的优先级和他一样,则还是自定义切面在内层,这时若自定义切面没有正确抛出
    异常,则事务切面不能接收到异常,就不能回滚
    
    解决:(1)需要将异常抛出去(推荐)   (2)调用 TransactionStatus.setRollbackOnly()方法通知回滚事务
    	 (3)@Order(Ordered.LOWEST_PRECEDENCE - 1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (4)非public方法

    原因:spring为方法创建代理、添加事务通知、前提条件都是该方法是public的
    
    解决:@Transactional 注解必须加在public方法上,不能加在其他方法上,必须加public修饰符
    
    • 1
    • 2
    • 3

    (5)父子容器

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

    (6)本类方法调用

    调用本类方法导致传播行为失效
    
    原因:本类方法调用不经过代理,因此无法增强
    
    解决:(1)依赖注入自己(代理)来调用    (2)通过AopContext拿到代理对象,来调用
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (7)原子性失效

    @Transactional没有保证原子行为
    
    原因:事务的原子性仅涵盖 insert  uodate  delete  select..for update 语句,select方法并不阻塞
    
    • 1
    • 2
    • 3

    (8)锁失效

    @Transactional方法导致的synchronized失效
    
    原因:synchronized保证的仅是目标方法的原子性,环绕目标方法的还有commit等操作,它们并未处在synchronized块内
    
    解决:(1)synchronized范围应扩大至代理方法调用   (2)使用 select..for update 替换 select(推荐使用)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.springMVC执行流程

    (1)初始化阶段

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

    (2)匹配阶段

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

    (3)执行阶段

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

    第二步没有异常

    第二步有异常

    5.一些注解

    (1)@Configuration

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

    (2)@Import

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

    (3)@SpringBootApplication

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

    6.spring中有哪些设计模式

    (1)单例模式

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

    (2)Builder模式

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

    (3)工厂方法模式

    让接口和实现相分离,降低耦合
    
    如:ApplicationContext 和 BeanFactory中的getBean
    
    • 1
    • 2
    • 3

    (4)Adapter适配器模式

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

    (5)组合模式

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

    (6)装饰器模式

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

    (7)Proxy 代理模式

    控制目标的访问
    
    • 1

    (8)责任链模式

    (9)观察者模式

    用来解耦合
    
    • 1

    (10)策略模式

    (11)模板方法设计模式

    7.循环依赖

    (1)创建代理

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

    (2)缓存

    (1)一级缓存

    作用:限制bean在beanFactory中只存一份,即实现 singleton scope
    
    问题:解决不了set循环依赖
    
    • 1
    • 2
    • 3


    (2)二级缓存

    作用:解决set循环依赖
    
    问题:不能解决set循环依赖中有代理的情况
    
    • 1
    • 2
    • 3


    (3)三级缓存

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

    (3)构造循环依赖

    三级缓存不能解决构造循环依赖
    
    解决:(1)用 @Lazy 注解(加在方法的参数前边),使用B的代理对象
    	 (2)用 ObjectFactory ,使用B的工厂对象
    	 (3)用 Provider,与ObjectFactory作用一样
    	 (4)用 @Scope 注解(加在类上面)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6



    (4)总结

  • 相关阅读:
    python面试题——版本管理工具GIT(二)
    Linux 创建 终止线程(thread)
    第三方支付“进件”是什么意思
    放大镜
    机器学习(一)
    idea上传不了github
    新的3D地图制图技术改变了全球定位的游戏规则
    基于批发价格指数的美国通货膨胀研究,数据从1960年第一季度至1990年第4季度的WPI(批发价格指数)共有124个数据,使用R中的ARIMA模型对该时间序列进行建模分析。
    基于蜉蝣优化的BP神经网络(分类应用) - 附代码
    Fourier变换中的能量积分及其详细证明过程
  • 原文地址:https://blog.csdn.net/weixin_56680764/article/details/128048636