Spring
Spring框架中的单例bean是线程安全的吗?
bean上面可以加入注解@Scope,如果是singleton(默认),意味着bean在每个spring IOC容器中只有一个实例;如果是prototype,说明一个bean定义可以有多个实例。spring框架没有对单例bean进行任何多线程的封装处理,关于单例bean的线程安全和并发安全需要开发者考虑
AOP
面向切面编程,将与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取封装成一个可重用的模块称为切面,减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。
核心:使用aop中的环绕通知+切点表达式,通过环绕通知的参数获取请求方法的参数(类、方法、注解、请求方式等),获取到这些参数以后,保存到数据库。
Spring事务本质就是通过AOP功能,对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交事务或者回滚。
Spring中事务失效的场景有哪些?
异常捕获处理:解决办法抛出异常
抛出检查异常(不是runtime):解决办法,在transactional中配置rollbackFor属性Exception
非public方法:改为public方法
Spring的Bean的生命周期
BeanDefinition:spring容器在进行实例化时,会将xml配置的bean的信息封装成一个BeanDefinition对象,根据这个对象来创建Bean对象,里面有很多属性描述Bean,如beanClassName:bean类名
initMethodName:初始化方法名
properryValues:bean的属性值
scope:作用域
lazyInit:延迟初始化
1. 通过BeanDefinition获取bean的定义信息
2. 调用构造函数实例化bean
3. bean的依赖注入
4. 处理Aware接口(BeanNameAware,BeanFactoryAware,ApplicationContextAware)
5. bean的后置处理器BeanPostProcessor-前置
6. 初始化方法(InitializingBean,init_method)
7. bean的后置处理器BeanPostProcessor-前置(AOP,动态代理等)
8. bean销毁destory
Spring中的循环引用
Spring的循环依赖
三级缓存
一级缓存:singletonObjects:单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象。
二级缓存:earlySingletonObjects:缓存早起的bean对象(生命周期还没走完)。
三级缓存:singletonFactories:缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的。
一级缓存作用:限制bean在beanFactory中只存一份,即实现singleton scope,解决不了循环依赖。
实例化A,先在堆内开辟内存空间得到半成品A,看到了b要设置b属性,因为b是B类型的对象,需要到spring容器查找对象,由于没有B,所以实例化B,在堆内开辟空间得到半成品B,之后初始化B,设置a属性后需要初始化A,造成循环。
二级缓存:做中间人
实例化A后得到原始对象A以后放入到二级缓存中(半成品),此时需要注入B,所以实例化B,得到一个原始对象B也放入到二级缓存中,此时需要注入A,从二级缓存中即可获取A,B创建成功注入给A,A也创建成功,放入到一级缓存中。
三级缓存:代理对象
实例化A,原始对象A生成一个ObjetFactory对象放入到三级缓存中,此时需要注入B所以进行实例化,生成一个objectfactory的b对象放入三级缓存,需要注入A,之后从三级缓存中拿到A的objectfactory对象创建代理对象放到二级缓存中,同时注入给B,后面一致。
如果构造方法中产生了循环依赖,由于bean的生命周期中构造函数是第一个执行的,spring框架并不能解决构造函数的依赖注入。在后面加入@Lazy注解进行懒加载,什么时候需要对象再进行bean对象的创建。
SpringMVC的执行流程
1. 用户发送出http请求到前端控制器DispatcherServiet
2. DispatcherServiet接收到请求调用处理器映射器HandlerMapping
3. HandlerMapping找到具体的处理器,生成处理器对象以及处理器拦截器,再一起返回给DispatcherServiet
4. DispatcherServiet调用处理器适配器HandlerAdapter
5. HandlerAdapter经过适配器调用具体的处理器(Handler/Controller)
6. 方法上添加了@ReaponseBody
7. 通过HttpMessageConverter来返回结果转换为JSON并响应
SpringBoot自动配置原理
@SpringBootApplication=
@SpringBootConfiguration:声明当前类是一个配置类
@ComponentScan:组件扫描当前引导类所在包及其子包
@EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解
其通过@Import注解注入导入对应的配置选择器,读取该项目和该项目引用的jar包的classpath路径下META-INF/spring.factories文件中的所配置类的全类名,在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的class文件,如果有则加载该类,把这个配置类所有的Bean放入spring容器中使用。
Spring常见注解
Mybatis
Mybatis执行流程
1. 读取MyBatis配置文件:mybatis-config.xml加载运行环境和映射文件
2. 构建会话工厂SqlSessionFactory
3. 会话工厂创建SqlSession对象(包含了执行SQL语句的所有方法)
4. 操作数据库接口,Executor执行器,同事负责查询缓存的维护
5. Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息
6. 输入参数映射:从java类型到sql类型
7. 输出结果映射:从sql转为jave类型
Mybatis延迟加载
查询用户的时候,把用户所属的订单数据也查询出来,这个是立即加载
查询用户的时候,暂时不查询订单数据,当需要订单的时候,再查询订单,这个就是延迟加载
延迟加载原理:
1. 使用CGLIB创建目标对象的代理对象
2. 当调用目标方法时,进入拦截器的invoke方法,发现目标方法是null,执行sql查询
3. 获取数据后,调用set方法设置属性值,再继续查询方法,就有值了
Mybatis一级二级缓存
一级缓存:基于PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Session进行flush或者close后,Cache清空,默认打开一级缓存
二级缓存;基于namespace和mapper的作用域起作用,不依赖session,默认也是采用perpetualcache,hashmap存储,需要单独开启,一个是核心配置,一个是mapper映射文件
二级缓存清理数据:当某个作用域(一级缓存session/二级缓存namespace)进行了增删改后,默认该作用域所有select中的缓存被clear。