一.ApplicationContext refresh 的流程

image.png

二.Spring Bean的生命周期

image.png

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

①先把别名解析为实际名称,在进行后续处理
②若要FactoryBean本身,需要使用&名称获取
③singletonObjects 是一级缓存,放单例成品对象
④singletonFactories 是三级缓存,放单例工厂(解决循环依赖)
⑤earlySingletonObjects 是二级缓存,放单例工厂的产品,可以为提前单例对象(解决代理训话依赖)

四.Spring事务失效(p152-159)

①抛出检查异常(语法上有强制要求的需要try catch/throw)导致事务不能正确回滚
原因:Spring默认只会回滚非检查异常 (Runtime Exception和Error子类)
解法:配置rollback属性 @Transaction(rollback=Exception.class)
②事务通知只有捉到了目标抛出的异常,才能进行后续的回滚操作,如果自己手动try catch,事务调用者得不到异常信息,无法回滚
解法1:异常原样抛出 throw new RuntimeException(e)
解法2:手动设置 TransactionInterceptor.currentTransactionStatus.setRollbackOnly()
③aop切面顺序导致事务不能正确回滚
image.png
原因:事务切面优先级最低,但如果自定义切面优先级和他一样,则还是自定义切面在内层,这时若自定义切面没有正确抛出异常则无法回滚
解法:同情况2
④非public方法导致事务失效
原因:Spring为方法创建代理,添加事务通知,前提条件都是该方法是public修饰的
⑤父子容器导致的事务失效
原因:子容器扫描范围过大,把未加事务配置的service扫描进来
解法1:各扫各的,不要图简便
解法2:不要用父子容器,所有的bean放在同一个容器(一般Spring MVC才会出现父子容器,Spring boot 不会)
⑥调用本类方法导致传播行为失效
image.png
原因:事务的本质是依靠代理,本类方法调用不经过代理,因此无法增强
解法1:依赖注入自己(代理)来调理
解法2:通过AopContext拿到代理对象,来调用
⑦@Transactional没有保证原子性行为,在多线程情况下,读取脏数据
原因:事务的原子性仅涵盖insert,update,delete,select…for update 语句,select方法不阻塞
image.png
⑧@Transactional方法导致synchronized失效
原因:synchronized保证的仅是目标方法的原子性,环绕目标方法还有commit等操作,它们并未处于sync块内
解法1:synchronized范围扩大至代理方法调用
image.png
解法2:使用select……for update 替换select(数据库层面)

五.Spring MVC的执行流程(p160-162)

初始化阶段:

image.png
1.在web容器第一次用到DispatcherServlet(由web容器tomcat触发创建的:传统的spring和mvc整合;在Springboot中由boot自身创建)的时候,会创建其对象并且执行init方法
2.init方法会创建Spring web容器,并且调用容器refresh方法
3.refresh过程中会创建并初始化SpringMVC中的重要组件
HandlerMapping:浏览器的请求映射到Spring控制器的方法上
HandlerAdapter:调用控制器的方法来处理请求
HandlerException Resolver:处理调用时出现的异常
ViewResolver:控制器方法执行完毕封装成ModelandView对象,视图可能只包含一个字符串的名字,将字符串解析成视图对象,跳转到jsp还是模板引擎
MultipartResovler:进行视图渲染工作;并不是必须的,文件上传的时候处理multipart格式表单数据
4.容器初始化后,会将上一步初始化好的重要组件,赋值给DispatcherServlet的成员变量,留待使用

匹配阶段:

image.png
1.用户发送的请求统一到达前端控制器 DispatcherServlet(入口并不负责处理请求)
2.DispatcherServlet遍历所有HandlerMapping,找到与路径匹配的处理器
①HandlerMapping有多个,每个HandlerMapping会返回不同的处理对象,谁先匹配,返回谁的处理器;其中能识别@RequestMapping的优先级最高
②对应@RequestMapping的处理器是HandlerMethod,它包含了控制器对象和控制器方法信息
③其中路径与处理器的映射关系在HandlerMapping初始化时就会建立好
3.将HandlerMethod连同匹配到的拦截器,生成调用链对象HandlerExecutionChain返回
4.遍历HandlerAdapter处理器适配器,找到能处理HandlerMethod的适配器对象,开始调用

执行阶段:

1.调用执行拦截器中的preHandle:由外到内==>返回值为true放行,false被拦截
2.HandlerAdapter(适配器)调用HandlerMethod(处理器)
①控制器的参数比较复杂request,response,cookie,session,模型model对象,请求参数==>通过method反射调用invoke(bean,参数)
②调用处理返回值:List,bean,map
没有异常:
image.png
①返回ModelAndView(模型数据和视图相关信息)
②执行拦截器postHandle方法,由内到外
③借助视图解析ViewResolver(如果返回的是名字解析成对象),得到View对象,进行视图渲染
④有内到外调用拦截器afterCompletion()
有异常:
①如果第2步有异常,进入HandlerExceptionResolver异常处理流程(不会返回ModelAndView)
②最后都会执行拦截器的afterCompletion方法
3.如果控制器的方法标注了@ResponseBody注解,则在第2步,就会生成json结果,并标记ModelAndView已经处理,这样就不会执行解析视图,视图渲染

六.Spring,MVC,Boot相关注解

Spring相关:

事务:
@Transaction:加在public方法上表示此方法受事务控制;加载类上此类所有public方法受事务控制
@EnableTransactionManagement:启用声明式事务控制,底层类似一个事务切面,拦截器拦截@Translation切入点,解析@Translation

@Order: 默认最小优先级,越大的优先级越低,越小的越高;控制bean的顺序
@EnableAspectJAutoProxy:启动aop自动代理
组件扫描与配置类:
@Component @Controller @Service @Repository 配合组件扫描的,Spring 容器管理配合@ComponentScan(指定起始包名,扫描当前类及其子类)
@Conditional :配合组件扫描/@Bean注解,加条件满足条件才会加入到IOC容器
@Configuration:配置类
@Bean:配置类中哪些方法是bean的定义
@Import:导入其他的配置类
@Lazy:标注在类上表示延时实例化,不用不创建;方法参数/成员变量解决循环依赖,依赖/参数注入创建代理对象,循环依赖走完了,要用到这个bean的时候才真正创建
@PropertySource:读取properties文件
依赖注入:
@Autowired:加在方法参数上/方法上 完成注入
@Qualifier:依赖注入时,同一类型有多个bean,根据名字注入区分
@Value:配合${},#{}实现值的读取

Spring MVC相关:

@RequestMapping:建立请求路径和控制器方法的映射关系;放在类上窄化路径
rest:
@RequestBody:请求体中的json数据转换成java中的对象,处理请求体
@ResponseBody:把java对象转换成json数据,处理响应体
@ResponseStatus:响应的状态码
@RestController:组合注解ResponseBody+@Controller
同一处理:
@ControllerAdvice:统一处理异常的方法,放在类中
@ExceptionHandler:在需要统一处理异常的方法上标注;组合使用同一类中:全局异常;放在单独的控制器中单独的异常处理
@RestControllerAdvice:@ResponseBody+@ControllerAdvice 异常处理转换成json格式,写入响应体
获取参数:
@RequestHeader:获取请求头中的信息
@PathVariable:获得请求路径中的数据
@RequestParam:获取请求参数中的?后面的键值形式/表单中的请求参数(不传参数可以设置默认值/只要名称一样可以省略)

@CrossOrigin:解决ajax的跨域问题,用在JS中的ajax

Spring Boot相关:

@ConfigurationProperties:将properties文件中的键值信息与javabean中的属性相同的赋值
image.png
@EnableConfiguartionProperties:启动上面注解
auto:
@SpringBootApplication:由下面两个注解组成+@ComponentScan 扫描启动类及其子类,排除过滤器
@EnableAutoConfiguration:找到自动配置类,自动配置类都会注册到spring容器中
@SpringBootConfiguration:Springboot的配置类底层是@Configuration

@Configuration注解:

①配置类其实相当于一个工厂,标注@Bean注解的方法相当于工厂方法(实例工厂/静态工厂)
②@Bean不支持方法重载,如果有多个重载方法,仅有一个能选为工厂方法(参数多的优先)
④@Configuration中如果含有BeanFactory后置处理器(spring refresh()第五步,而配置类在第十一步才能解析@Value@Autowired),则实例工厂方法会导致MyConfig提前创建,造成其依赖注入失败(可以修改器值)
③@Configuration 默认会为标注的类生成代理,其目的是保证@Bean方法相互调用的时候,仍然能保证其单例
解决方法:使用该静态方法或直接@Bean依赖注入,针对MapperScanner可以用注解方式
image.png

@Import注解:

image.png
image.png
image.png

SpringBoot的自动配置

@EnableAutoConfiguration
@AutoConfiguartionPackage:用来记住起始的包
@Import(AutoConfigurationImportSelector.class)用来加载classpath下的 META-INF/spring.factories 中的自动配置类

image.png
image.png
image.png
2697a3442a03de7392a1fa403ec56b9.png
SpringBoot 2.3.10 127个 XXAutoConfiguration 自动化配置类需要初始化,但是需要满足条件才可以被初始化

1、SpringBoot如何获取到所有的自动化配置? 实例化?

通过EableAutoconfiguration类加载AutoConfigurationImportSelector类下面的selectImport方法:META-INF/spring.factories 配置文件中

2、这些自动化配置的类是否会全部生效? 为什么?

image.png
不会全部生效,取决于在类和方法上 @ConditionalOnXXX 条件注解,如果全部满足条件,则会初始化bean到IOC容器中

3、如果自动化配置的类生效了,默认的配置是什么? 怎么获取的?

image.png
配置属性对象的默认值,并且也提供了自定义配置,通过application.yml配置文件中只需要按照预先约定进行配置即可
约定值: RedisProperties写死的值port=6379
@ConfigurationProperties(prefix = “spring.redis”) 可以通过配置文件
spring.redis.port = 9999
读取后通过 setPort(9999) 设置到port属性,就会将默认值覆盖

七.Spring循环依赖(p176-199)

1.proxyFactory创建代理的过程,Advisor,Advice,Poincut,Aspect

Aspect=通知(advic)+切点(pincout),一个切面类中可能有一到多个通知方法,每一个通知都会变成advisor
Advisor:更细粒度的切面,包含一个通知和切点,前置,后置,环绕,所有的通知都实现了MethodInterceptor
image.png
image.png
image.png

2.set方法循环依赖

一级缓存:防止bean重复创建

作用:限制bean在beanFactory中只存一份,实现singleton scope(存在获取,不存在创建)
image.png
一级缓存解决不了循环依赖,A创建对象需要依赖B,B创建对象需要依赖A

二级缓存:解决循环依赖

image.png
①当创建A对象时,先将半成品a放入到singletonFactories中
②在注入b对象时,先从factories中获取(第一次为null)
③getBean(b)创建b对象,创建b的时候会再一次将b的对象放入到singletonFactories中
④⑤然后从其中获取a的依赖完成注入
⑥初始化b对象,返回给a,完成b的依赖注入
image.png

三级缓存:解决循环依赖代理问题

image.png

3.构造方法循环依赖

创建Spring工厂对象,延迟bean的创建

image.png

创建Java工厂对象,延迟bean的创建

image.png

使用Spring@Lazy注解

image.png

使用Spring@Scope注解

image.png

总结:

image.png