Spring原理
# Spring原理
# IOC理解
- 控制反转:原来由对象使用者控制的,有了spring后,整个生命周期由容器管理
- 依赖注入:将对应属性注入到具体对象中,用 @Autowired,@Resource,@PopulateBean 来完成属性填充
- 容器:使用map存储对象,在存储过程中有三级缓存,用 sigletonObjects 存储完整对象(一级), earlySigletonObject 存储半成品对象(二级), sigletonObjectFactory 存放lamba表达式和对象名称映射
# 单例Bean和单例模式
单例模式表示JVM中某个类的对象只会存在唯⼀⼀个。 ⽽单例Bean并不表示JVM中只能存在唯⼀的某个类的Bean对象。
# Spring事务传播机制
多个事务⽅法相互调⽤时,事务如何在这些⽅法间传播,⽅法A是⼀个事务的⽅法,⽅法A执⾏过程中调 ⽤了⽅法B,那么⽅法B有⽆事务以及⽅法B对事务的要求不同都会对⽅法A的事务具体执⾏造成影响, 同时⽅法A的事务对⽅法B的事务执⾏也有影响,这种影响具体是什么就由两个⽅法所定义的事务传播类 型所决定。
- REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则⾃⼰新建⼀个事务,如果当前存 在事务,则加⼊这个事务
- SUPPORTS:当前存在事务,则加⼊当前事务,如果当前没有事务,就以⾮事务⽅法执⾏
- MANDATORY:当前存在事务,则加⼊当前事务,如果当前事务不存在,则抛出异常。
- REQUIRES_NEW:创建⼀个新事务,如果存在当前事务,则挂起该事务。
- NOT_SUPPORTED:以⾮事务⽅式执⾏,如果当前存在事务,则挂起当前事务
- NEVER:不使⽤事务,如果当前事务存在,则抛出异常
- NESTED:如果当前事务存在,则在嵌套事务中执⾏,否则REQUIRED的操作⼀样(开启⼀个事 务)
# Spring事务什么时候会失效?
spring事务的原理是AOP,进⾏了切⾯增强,那么失效的根本原因是这个AOP不起作⽤了!常⻅情况有 如下⼏种
- 发⽣⾃调⽤,类⾥⾯使⽤this调⽤本类的⽅法(this通常省略),此时这个this对象不是代理类,⽽是 UserService对象本身! 解决⽅法很简单,让那个this变成UserService的代理类即可!
- ⽅法不是public的:@Transactional 只能⽤于 public 的⽅法上,否则事务不会失效,如果要⽤在 ⾮ public ⽅法上,可以开启 AspectJ 代理模式。
- 数据库不⽀持事务
- 没有被spring管理
- 异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)
# Spring中的Bean创建的⽣命周期
Bean的整个生命周期都是容器来控制的,其主要包含实例化和初始化
- 实例化Bean有 CreatBeanInstance 方法来生成对象
- 由 populateBean 来填充属性
- 向Bean对象中设置容器属性,会调用 invokeAwareMethods 方法来将容器对象设置到具体的Bean对象中
# Spring中Bean是线程安全的吗
Spring本身并没有针对Bean做线程安全的处理
所以:
- 如果Bean是⽆状态的,那么Bean则是线程安全的
- 如果Bean是有状态的,那么Bean则不是线程安全的
- 另外,Bean是不是线程安全,跟Bean的作⽤域没有关系,Bean的作⽤域只是表示Bean的⽣命周期范 围,对于任何⽣命周期的Bean都是⼀个对象,这个对象是不是线程安全的,还是得看这个Bean对象本 身
# ApplicationContext和BeanFactory的区别
BeanFactory是Spring中⾮常核⼼的组件,表示Bean⼯⼚,可以⽣成Bean,维护Bean,⽽ ApplicationContext继承了BeanFactory,所以ApplicationContext拥有BeanFactory所有的特点,也 是⼀个Bean⼯⼚,但是ApplicationContext除开继承了BeanFactory之外,还继承了诸如 EnvironmentCapable、MessageSource、ApplicationEventPublisher等接⼝,从⽽ ApplicationContext还有获取系统环境变量、国际化、事件发布等功能,这是BeanFactory所不具备的
# Spring中的事务是如何实现的
- Spring事务底层是基于数据库事务和AOP机制的
- ⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean
- 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解
- 如果加了,那么则利⽤事务管理器创建⼀个数据库连接
- 并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮ 常重要的⼀步
- 然后执⾏当前⽅法,⽅法中会执⾏sql
- 执⾏完当前⽅法后,如果没有出现异常就直接提交事务
- 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
- Spring事务的隔离级别对应的就是数据库的隔离级别
- Spring事务的传播机制是Spring事务⾃⼰实现的,也是Spring事务中最复杂的
- Spring事务的传播机制是基于数据库连接来做的,⼀个数据库连接⼀个事务,如果传播机制配置为 需要新开⼀个事务,那么实际上就是先建⽴⼀个数据库连接,在此新数据库连接上执⾏sql
# Spring中什么时候@Transactional会失效
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效,所以如果是被代理对象来调⽤这个⽅法,那么@Transactional是不会失效的。 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效
# Spring容器启动流程是怎样的
- 在创建Spring容器,也就是启动Spring时:
- ⾸先会进⾏扫描,扫描得到所有的BeanDefinition对象,并存在⼀个Map中
- 然后筛选出⾮懒加载的单例BeanDefinition进⾏创建Bean,对于多例Bean不需要在启动过程中去进 ⾏创建,对于多例Bean会在每次获取Bean时利⽤BeanDefinition去创建
- 利⽤BeanDefinition创建Bean就是Bean的创建⽣命周期,这期间包括了合并BeanDefinition、推断 构造⽅法、实例化、属性填充、初始化前、初始化、初始化后等步骤,其中AOP就是发⽣在初始化 后这⼀步骤中
- 单例Bean创建完了之后,Spring会发布⼀个容器启动事件
- Spring启动结束
- 在源码中会更复杂,⽐如源码中会提供⼀些模板⽅法,让⼦类来实现,⽐如源码中还涉及到⼀些 BeanFactoryPostProcessor和BeanPostProcessor的注册,Spring的扫描就是通过 BenaFactoryPostProcessor来实现的,依赖注⼊就是通过BeanPostProcessor来实现的
- 在Spring启动过程中还会去处理@Import等注解
# Spring⽤到了哪些设计模式
# Spring Boot中常⽤注解及其底层实现
- @SpringBootApplication注解:这个注解标识了⼀个SpringBoot⼯程,它实际上是另外三个注解的 组合,这三个注解是: a. @SpringBootConfiguration:这个注解实际就是⼀个@Configuration,表示启动类也是⼀个 配置类 b. @EnableAutoConfiguration:向Spring容器中导⼊了⼀个Selector,⽤来加载ClassPath下 SpringFactories中所定义的⾃动配置类,将这些⾃动加载为配置Bean c. @ComponentScan:标识扫描路径,因为默认是没有配置实际扫描路径,所以SpringBoot扫 描的路径是启动类所在的当前⽬录
- @Bean注解:⽤来定义Bean,类似于XML中的bean标签,Spring在启动时,会对加了@Bean注 解的⽅法进⾏解析,将⽅法的名字做为beanName,并通过执⾏⽅法得到bean对象
- @Controller、@Service、@ResponseBody、@Autowired类似
# AOP原理
- 对Bean进行扩展,在beanPostProcessor方法
- 用advice进行切面,切点
- 通过JDK或者cglib来生成代理对象
- 在方法调用中,会调用到生成字节码文件中直接找到DynamicAdvisoredInterceptor中的Interceptor方法,根据定义好的通知,来生成拦截器
# Tomcat启动原理
- 启动spring容器
- @ConditionalOnClass来判断当前classpath中是否存在Tomcat依赖,如果存在则生成一个启动Tomcat的Bean
- 启动Tomcat的Bean,并创建Tomcat对象,并且绑定端口等,然后启动Tomcat
# BeanFactory 和 FactoryBean区别
BeanFactory必须严格遵守Bean的生命周期,创建单例Bean是流水式创建过程 FactoryBean可以自定义Bean对象创建流程,不需要遵循Bean生命周期,比如Feign
# spring如何解决循环依赖
三级闭环,提前暴露和aop
# spring自动装配过程
- 通过各种注解实现了类与类之间的依赖关系,容器在启动的时候SpringApplication.run(),调用EnableAutoConfigurationImportSelector.class的selectImports方法
- selectImports方法调用SpringFactoriesLoader.loadFactoryNames方法扫描jar包类路径下的META-INF/spring.factories文件下,获取BeanConfiguration列表
- loadFactoryNames方法会读取spring.factories中EnableAutoConfiguration.class类名对应的值
- 根据这些类上的注解判断,若条件满足,则该配置类生效,将配置文件中自己设置的属性值配置到对应的配置类中,最后注入到IOC容器中实现自动配置
总结 Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖