Spring 是一个 IOC 和 AOP 容器框架。
## 控制反转(IOC) ##
传统的 java 开发模式中,当需要一个对象时,我们会自己使用 new 或者 getInstance 等直接或者间接调用构造方法创建一个对象。而在 spring 开发模式中,spring 容器使用了工厂模式为我们创建了所需要的对象,不需要我们自己创建了,直接调用 spring 提供的对象就可以了,这是控制反转的思想。
## 依赖注入(DI) ##
spring 使用 javaBean 对象的 set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程,就是依赖注入的思想。
## 面向切面编程(AOP) ##
在面向切面编程中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。AOP 底层是动态代理,如果是接口采用 JDK 动态代理,如果是类采用CGLIB 方式实现动态代理。
**动态代理**
AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
(1)JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
(2)如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
*InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。
** 事务的并发会产生的问题有哪些 **
## 1.脏读 ##
一个事务正在对数据进行更新操作,但是更新还未提交,另一个事务这时也来操作这组数据,并且读取了前一个事务还未提交的数据,而前一个事务如果操作失败进行了回滚,后一个事务读取的就是错误的数据,这样就造成了脏读
## 2.不可重复读 ##
一个事务多次读取同一个数据,在该事务还未结束时,另一个事务也对该数据进行了操作,而且在第一个事务两次读取之间,第二个事务对数据进行了更新,那么第一个事务前后两个读取到的数据是不同的,这样就造成了不可重复读
## 3.幻读 ##
第一个事务正在查询某一条数据,这时,另一个事务又插入了一条符合条件的数据,第一个事务在第二次查询符合同一条件的数据时,发现多了一条前一次查询时没有的数据,仿佛幻觉一样,这就是幻读
## 不可重复读和幻读的区别 ##
不可重复读是指在同一查询事务中多次进行,由于其他提交事务所做的修改和删除,每次返回不同的结果集,此时发生不可重复读。幻读是指在同一查询事务中多次进行,由于其他提交的事务所做的插入操作,每次返回不同的结果集,此时发生幻读表面上看,区别就在于不可重复读能看见其他事务提交的修改和删除,而幻读能看见其他事务提交的插入
## spring 事务隔离级别 ##
1.default:(默认)
默认隔离级别,使用数据库默认的事务隔离级别
2.read_uncommitted:(读未提交)
这是事务最低的隔离级别,他允许另外一个事务可以看到这个事务未提交的数据,这种隔离级别会产生脏读,不可重复读和幻读
3.read_committed(读已提交)
保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据.这种事务隔离级别可以避免脏读,但是可能会出现不可重复读和幻读
4.repeatable_read(可重复读)
这种事务级别可以防止脏读,不可重复读.但是可能出现幻读.他除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读
5.Serializable 串行化
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。防止了脏读、不可重复读、幻读
总结:
脏读 不可重复读 幻读
读未提交 会 会 会
读已提交 不会 会 会
可重复读 不会 不会 会
串行化 不会 不会 不会
# spring事务的传播行为 #
1.requierd
如果有事务那么加入事务,没有的话新建一个
2.not_supported
不开启事务
3.requires_new
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完,继续执行老事务
4.mandatory
必须在一个已有的事务中执行,否则抛出异常
5.never
必须在一个没有的事务中执行,否则抛出异常
6.supports
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务那就不用事务
7.PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
# Spring声明式事务的回滚机制 #
在Spring 的事务框架中推荐的事务回滚方法是,在当前执行的事务上下文中抛出一个异常。如果异常未被处理,当抛出异常调用堆栈的时候,Spring 的事务框架代码将捕获任何未处理的异常,然后并决定是否将此事务标记为回滚。在默认配置中,Spring 的事务框架代码只会将出现runtime, unchecked 异常的事务标记为回滚;也就是说事务中抛出的异常时RuntimeException或者是其子类,这样事务才会回滚(默认情况下Error也会导致事务回滚)。在默认配置的情况下,所有的 checked 异常都不会引起事务回滚。如果有需要,可以通过rollback-for 和no-rollback-for进行指定。
# Spring Bean的生命周期。 #
bean 定义:在配置文件里面用<bean></bean>来进行定义。
bean 初始化:有两种方式初始化:
1.在配置文件中通过指定 init-method 属性来完成
2.实现 org.springframwork.beans.factory.InitializingBean 接口
bean 调用:有三种方式可以得到 bean 实例,并进行调用
bean 销毁:销毁有两种方式
1.使用配置文件指定的 destroy-method 属性
2.实现 org.springframwork.bean.factory.DisposeableBean 接口
# Spring 支持的几种 bean 的作用域。 #
Spring 框架支持以下五种 bean 的作用域:
singleton : bean 在每个 Spring ioc 容器中只有一个实例。
prototype:一个 bean 的定义可以有多个实例。
request:每次 http 请求都会创建一个 bean,该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。
session :在一个 HTTP Session 中,一 个 bean 定义对应一个实例。该作用域仅在基于 web 的Spring ApplicationContext 情形下有效。
global-session:在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的Spring ApplicationContext 情形下有效。
缺省的 Spring bean 的作用域是 Singleton。
# 注解开发代码怎么写的,问注解里面是怎么实现的? #
*
注解的定义通过@interface符号,注解中有属性,可以设置默认值,value是特殊属性,可以在单个赋值省略。注解是用来取代配置文件的,通过反射获取注解属性后进行操作。
# Ioc通过一个注解实现依赖注入,里面代码是怎么实现的? #
* 五步:1通过读取配置文件bean节点信息获取class
2 反射创建对象信息
3 获取字节码中的私有字段或者公有属性
4判断是否有指定注解类型
5 有指定就反射赋值