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)总结
转载:https://blog.csdn.net/weixin_56680764/article/details/128048636
查看评论