MVC
HTTP请求处理流程
参数绑定
- 不同注解修饰的参数都有支持的方法参数处理器,例如@RequestParam对应的是RequestParamMethodArgumentResolver
- 在请求处理流程中的调用目标方法环节,会使用对应的参数处理器解析参数
过滤器、拦截器、AOP执行顺序
IOC
bean的加载过程
- 注册BeanFactory后置处理器
- 通过BeanFactory后置处理器扫描出所有需要spring管理的类
- 通过BeanFactory后置处理器封装成BeanDefinition加载到BeanFactory
- 创建非延迟加载的bean实例
Bean实例化的过程
- 执行实例化前操作
- 创建Bean实例
- 将Bean缓存起来
- 给Bean填充属性值
- 初始化Bean
(1) 执行BeanPostProcessor-postProcessBeforeInitialization
(2) 执行InitializingBean->afterPropertiesSet
(3) 执行initMethod
(4) 执行BeanPostProcessor-postProcessAfterInitialization
spring是如何解决属性循环依赖的
Bean实例化的过程如上,第三步缓存bean就是为了解决循环依赖的,例如:A与B属性循环依赖。
- A执行第二,三步,调用构造函数并将实例加入缓存;
- A执行第四步时找不到B实例,于是先去执行B的实例化;
- B执行到第4步时从缓存中能够找到A实例,于是B实例化成功;
- 接着再执行A的实例化。
为什么spring无法解决构造方法中的循环依赖
调用构造函数后是第二步就要执行的事情,第二步都通过不了,自然就无法执行第三步加入缓存中。
Bean的生命周期
- BeanDefined
- BeanFactoryPostProcessor对BeanDefined后置处理
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation实例化前执行
- Bean实例化
- InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation实例化后执行
- 属性注入
- BeanNameAware.setBeanName
- BeanFactoryAware.setBeanFactory
- ApplicationContextAware.setApplicationContext
- BeanPostProcessor的前置方法
- InitializingBean.afterPropertiesSet方法
- @PostConstruct修饰的方法
- BeanPostProcessor的后置操作
- DisposableBean.destory销毁
- @PreDestroy修饰的方法
有几种注入方式
set 注入,构造器注入和方法注入
BeanFactory和FactoryBean的区别
- BeanFactory是Spring容器中的一个很重要的类,它对于Bean的创建有一个统一的流程
- FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程
spring的工厂模式是怎么实现的?
- spring的工厂模式实际上是抽象工厂模式
- 它允许用户为指定Bean自定义工厂
- 其他Bean会采用默认的一套流程生成Bean
自定义工厂类
- 自定义工厂类实现FactoryBean接口
- 实现getObject方法(获取对象的方法)
- @Component改名
AOP
代理模式有哪几种
静态代理、JDK动态代理、CGLib动态代理
- 静态代理,即对象的适配器模式
- JDK动态代理,生成被代理接口的匿名类作为代理类
- 动态代理类实现InvocationHandler接口
- Proxy.newProxyInstance生成代理对象
- 被代理类需要有接口
- CGLib动态代理,生成被代理类的子类作为代理类
- 创建Enhancer
- 创建MethodInterceptor接口实现类
- Enhancer.setSuperclass(被代理类)
- Enhancer.setCallback
- Enhancer.create生成代理类
JDK动态代理的原理
- 为接口创建代理类的字节码文件
- 使用ClassLoader将字节码文件加载到JVM
- 创建代理类实例对象,执行对象的目标方法
- 通过反射方式调用被代理类相应的方法
springboot如何选择代理模式
- 有接口,使用JDK动态代理(1.8后JDK动态代理效率高于CGLib动态代理)
- 无接口,使用CGLib动态代理
MyBatis
事务控制的原理
- 调用spring管理的bean的方法,实际上是通过代理类实现的
- 当识别到方法被@ Transactional修饰时,会执行事务拦截器
- 在事务拦截器中,开启事务
- 在事务拦截器中,调用目标对象方法
- 在事务拦截器中,提交事务或者回滚事务。
事务传播行为
- REQUIRED (要求):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- SUPPORTS (支持):如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- MANDATORY (强制):如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- REQUIRES_NEW (要求新的):创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- NOT_SUPPORTED (不支持):以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- NEVER (都不):以非事务方式运行,如果当前存在事务,则抛出异常。
- NESTED (嵌套):如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED 。
- 指定方法:通过使用 propagation 属性设置,例如:@Transactional(propagation = Propagation.REQUIRED)
- 默认值为REQUIRED
JDBC四大核心类
- DriverManager,用于注册数据库连接
- Connection,与数据库连接对象
- Statement/PrepareStatement,操作数据库SQL语句的对象
- ResultSet,结果集或一张虚拟表
MyBatis也有四大核心类:
- SqlSession对象,该对象中包含了执行SQL语句的所有方法。类似于JDBC里面的Connection。
- Executor接口,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。类似于JDBC里面的Statement/PrepareStatement。
- MappedStatement对象,该对象是对映射SQL的封装,用于存储要映射的SQL语句的id、参数等信息。
- ResultHandler对象,用于对返回的结果进行处理,最终得到自己想要的数据格式或类型。可以自定义返回类型。
Mybatis 原理
在spring中,Mapper接口我们都没有实现的方法却可以通过依赖注册的方式使用,是为什么呢?
- mybatis使用动态代理的方式实现了Mapper接口
- MapperFactoryBean,spring动态代理的方式将实现的mapper对象又进行了一层分装
- 最终,当执行mapper时,将先去获取ThreadLocal中获取sqlSession,无则创建,然后调用sqlsession.Mapper的方式获得到最终的Mapper对象。
一级缓存和二级缓存
- 一级缓存是sqlsession级别的缓存,当调用close/clearCache或udpate时清空缓存,由于无事务时,一条sql的执行就会调用close方法,所以一级缓存只作用无同一事务中。
- 二级缓存是应用级别的缓存,以namespace为维度。当namespace下发生增删改操作时清空缓存,分布式环境和多表操作存在问题,不推荐使用。
其他
springboot的启动流程
springboot自动装配原理
- Import相关
- 注解嵌套关系 @SpringBootApplication -> @EnableAutoConfiguration注解 -> @Import({AutoConfigurationImportSelector.class})
- Import会将selectImports方法返回的所有全路径限定类名都会被spring扫描
- AutoConfigurationImportSelector相关
- 核心方法调用链 selectImports -> getAutoConfigurationEntry -> getCandidateConfigurations -> loadSpringFactories
- 将扫描classpath下面类路径为META-INF/spring.factories的所有文件(包括jar包),提取出key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有数据。
- ConditionalOnClass注解
- 官方组件一般都被ConditionalOnClass注解修饰,这是由于官方组件factories文件都不和jar包放一起。
- 它表示标记的类存在时才会被spring装配,即导入了目标jar包时才会被spring装配
当spring的事务隔离级别同mysql的事务隔离级别不一致时
- jdbc 的使用流程有四部,注册驱动,建立连接,发起请求,输出结果
- 其中建立连接可以指定事务隔离级别
- 于是当spring设置的事务隔离级别同数据库不一致时,以spring为准。
@Transactional不起作为的四个原因
- 默认RuntimeException异常才回滚,可指定
- 异常捕捉后没有抛出
- 修饰非public方法(事务拦截器实现的,当为非public方法时不会去获取Transactional注解信息)
- 在类内部调用调用类内部@Transactional标注的方法(由于动态代理的机制,可以通过将内部方法调用替换为代理类方法调用来避免)
- 修饰接口,只有通过JDK动态代理才能起作用。
- 存储引擎
- 事务传播等级
springboot有哪些优点
- 独立运行,内嵌了各种 servlet 容器,Tomcat、Jetty 等,现在不再需要打成war 包部署到容器中,Spring Boot 只要打成一个可执行的 jar 包就能独立运行,所有的依赖包都在一个 jar 包内
- 简化配置,spring-boot-starter-web 启动器自动依赖其他组件,简少了 maven 的配置。
- 自动配置,能根据当前类路径下的类、jar 包来自动配置 bean,如添加一个 spring
boot-starter-web 启动器就能拥有 web 的功能,无需其他配置。 - 无代码生成和XML配置,配置过程中无代码生成,也无需 XML 配置文件就能完成所有配置工作,这一切都是借助于条件注解完成的
- 应用监控
spring-boot-starter-parent的作用
- 统一版本
- 指定编码
springboot如何多环境快速切换
- 添加application-dev.properties
- application.properties文件中添加配置
spring.profiles.active = dev
springboot如何实现热部署
导入spring-boot-devtools包
springboot封装starter组件核心
- resources目录下创建META-INF/spring.factories文件,定义要被spring管理的配置文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.mystarter.config.MyConfig
- 可在类上添加@Conditional标签限定实例化条件。
Spring Boot 配置加载顺序
- properties文件;
- YAML文件;
- 系统环境变量;
- 命令行参数;
Spring Boot做了什么
- 简化配置
- 起步依赖
- 内嵌容器
注解大全