一、关于Spring中的作用域
在Spring中使用Scope来表示一个bean定义对应产生实例的类型,也可以说是对应实例的作用范围。Spring内置支持的scope严格来说默认是有五种,分别是:
1.singleton:这是默认Scope,表示在整个bean容器中或者说是整个应用中只会有一个实例。
2.rototype:多例类型,表示每次从bean容器中都会获取到一个对应bean定义全新的实例。
3.request:仅适用于Web环境下的ApplicationContext,表示每一个HttpRequest生命周期内会有一个单独的实例,即每一个Http请求都会拥有一个单独的实例。
4.session:仅适用于Web环境下的ApplicationContext,表示每一个HttpSession生命周期内会有一个单独的实例,即每一个HttpSession下都会拥有一个单独的实例,即每一个用户都将拥有一个单独的实例。
5.globalSession:仅适用于Web环境下的ApplicationContext,一般来说是Portlet环境下。表示每一个全局的Http Session下都会拥有一个单独的实例。 application:仅适用于Web环境下的ApplicationContext,表示在ServletContext生命周期内会拥有一个单独的实例,即在整个ServletContext环境下只会拥有一个实例。
二、Spring在TransactionDefinition接口中规定的7种类型的事务传播行为
首先需要明确什么是事务传播行为?
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何运行。
那么在Spring中一共定义了七种事务传播行为:
1.PROPAGATION_REQUIRED(默认选择)
如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。
2.PROPAGATION_SUPPORTS
支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
3.PROPAGATION_MANDATORY
支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
4.PROPAGATION_REQUIRES_NEW
创建新事务,无论当前存不存在事务,都创建新事务。
5.PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
三、关于@AutoWired注解的问题
在使用@Autowired注解时,如果一个类可以有多种类型,就会对Spring IoC 容器注入造成困扰,这种情况我们称之为歧义性,为解决这一问题,我们可以使用@Qualifier注解;当发现有多种类型的Bean时,@Primary注解会通知IoC容器优先使用它所标注的Bean进行注入;@Quelifier注解可以与@AutoWired注解组合使用,达到通过类型和名称一起筛选Bean的效果。
简单总结:
@Autowired
注入声明的SpringBean对象,根据一定的规则首先按照注入的类型去查找,如果没有找到安装注入的名称去匹配你要注入的属性名称,如果都没有找到启动项目时抛出异常,@Autowired(required = false) 表示没有找到注入对象时,不抛异常,注入null。
@Primary
如果有多个相同类型的SpringBean,我们可以使用@Primary注解,优先注入带该注解标识的类,@Primary可以在多个类上标注,那就会抛异常。
@Quelifier
使用SpringBean的名称(SpringBean的名称都是唯一的)进行注入。
四、Spring的几种事务隔离级别
default(默认)
PlatfromTransactionManager默认的隔离级别
使用数据库默认的事务隔离级别,
除了default 其它几个Spring事务隔离级别与JDBC事务隔离级别相对应
read_uncommited(读未提交)
一个事务可以读取另外一个事务未提交的数据
这可能出现脏读 而且不可重复度,出现幻像读等.
read_commited(读已提交)
一个事务可以读取另一个事务已经提交的数据
不可以读取未提交的数据
可以避免脏读 但是无法避免不可重复读和幻像读
repeatTable_read(可重复读)
一个事务可以读取另外一个事务已经提交的数据
可以避免脏读的前提下 也可以避免不可重复读
但是还是无法避免幻像读
serializable(串行化)
这是一个花费较高但是比较可靠的事务隔离级别
可以避免脏读 幻像读和不可重复读
(事务被处理为顺序执行)
ps:关于几种脏读以及不可重复读的定义再记录一次:
首先对数据库事务的ACID特性进行复习:
A(Atomicity 原子性):任何事务都具备原子性,也就是说事务里的操作要么都执行,要么都不执行。
C(Consistent 一致性):在事务开始之前和完成之后,数据都必须保持一致状态,必须保证数据库的完整性。也就是说,数据必须符合数据库的规则。
I(Isolation 隔离性):数据库允许多个并发事务同事对数据进行操作,隔离性保证各个事务相互独立,事务处理时的中间状态对其它事务是不可见的,以此防止出现数据不一致状态。可通过事务隔离级别设置:包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
D(Durable 持久性):一个事务处理结束后,其对数据库的修改就是永久性的,即使系统故障也不会丢失。
现在回头看看Mysql的几种数据隔离级别:
首先 MySQL 里有四个隔离级别:Read uncommttied(可以读取未提交数据)、Read committed(可以读取已提交数据)、Repeatable read(可重复读)、Serializable(可串行化)。在使用InnoDB引擎的时候,默认的级别就是Repeatable,InnoDB 中使用一种被称为 next-key locking 的策略来避免幻读(phantom)现象的产生。
那么什么是脏读,不可重复读和幻读呢?
脏读:所谓脏读是指一个事务中访问到了另外一个事务未提交的数据;
幻读:一个事务读取2次,得到的记录条数不一致;
不可重复读:一个事务读取同一条记录2次,得到的结果不一致。
那么不同的隔离级别的解决方案对应能够解决什么问题呢?
1.未授权读
也称为读未提交(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。
2.授权读取
也称为读提交(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
3.可重复读取
可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
4.序列化
序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。、
不同的隔离级别对于性能的影响不同,根据具体的情况选择合适的隔离级别。
五、SpringBoot中独特的那些个注解
1.@Configuratio
@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
@Configuration
public class TaskAutoConfiguration {
@Bean
@Profile("biz-electrfence-controller")
public BizElectrfenceControllerJob bizElectrfenceControllerJob() {
return new BizElectrfenceControllerJob();
}
@Bean
@Profile("biz-consume-1-datasync")
public BizBikeElectrFenceTradeSyncJob bizBikeElectrFenceTradeSyncJob() {
return new BizBikeElectrFenceTradeSyncJob();
}
}
@Profile注解是用于指定代码的环境,因为在开发的过程中会涉及到开发环境和生产环境等,使用@Profile可以注入符合当前环境的bean (实际使用还有很多注意事项,之后再单独整理)。
2.@ComponentScan
点开常用的Controller,Service注解会发现他们有一个共同的注解@Component,@ComponentScan就是扫描指定的包是否包含了这些特定的注释
@ComponentScan(value = "com.abacus.check.api")
public class CheckApiApplication {
public static void main(String[] args) {
SpringApplication.run(CheckApiApplication.class, args);
}
}
3.@Conditional
@Conditional是Spring4新提供的注解,通过@Conditional注解可以根据代码中设置的条件装载不同的bean,在设置条件注解之前,先要把装载的bean类去实现Condition接口,然后对该实现接口的类设置是否装载的条件。Spring Boot注解中的@ConditionalOnProperty、@ConditionalOnBean等以@Conditional*开头的注解,都是通过集成了@Conditional来实现相应功能的。
4.@Import
通过导入的方式实现把实例加入springIOC容器中。可以在需要时将没有被Spring容器管理的类导入至Spring容器中。
5.@EnableAutoConfiguration
这个注解是启动SpringBoot的自动配置机制,帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot,并创建对应配置类的Bean,并把该Bean实体交给IoC容器进行管理。(还有一些具体的解释因为自己也没有接触过,没法理解)
补充:
该注解由组合注解@SpringBootApplication引入。
该注解作用是开启Spring Boot自动配置。
该注解会扫描各个jar包下的spring.factories文件,并加载文件中注册的AutoConfiguration类等。
@EnableAutoConfiguration的关键功能是通过@Import注解导入的ImportSelector来完成的。
6.SpringApplication调用的run方法执行流程
1. 初始化监听器,以及添加到SpringApplication的自定义监听器。
2. 发布ApplicationStartedEvent事件,如果想监听ApplicationStartedEvent事件,你可以这样定义:public class ApplicationStartedListener implements ApplicationListener,然后通过SpringApplication.addListener(..)添加进去即可。
3. 装配参数和环境,确定是web环境还是非web环境。
4. 装配完环境后,就触发ApplicationEnvironmentPreparedEvent事件。
5. 如果SpringApplication的showBanner属性被设置为true,则打印启动的Banner。(这个Banner就是启动成功的时候控制台答应出来的那个Spring的标志)
6. 创建ApplicationContext,会根据是否是web环境,来决定创建什么类型的ApplicationContext。
7. 装配Context的环境变量,注册Initializers、beanNameGenerator等。
8. 发布ApplicationPreparedEvent事件。
9. 注册springApplicationArguments、springBootBanner,加载资源等
10. 遍历调用所有SpringApplicationRunListener的contextLoaded()方法。
11. 调用ApplicationContext的refresh()方法,装配context beanfactory等非常重要的核心组件。
12. 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。
13. 发布ApplicationReadyEvent事件,启动完毕,表示服务已经可以开始正常提供服务了。通常我们这里会监听这个事件来打印一些监控性质的日志,表示应用正常启动了。
还有一部分常用的内容没有列出来,包括一部分奇奇怪怪的内容以后会添加。。。。