欢迎访问我的blog http://www.codinglemon.cn/

立个flag,8月20日前整理出所有面试常见问题,包括有:
Java基础、JVM、多线程、Spring、Redis、MySQL、Zookeeper、Dubbo、RokectMQ、分布式锁、算法。

7. Spring篇

文章目录

  • 7. Spring篇
    • 7.1 Spring的6大特征
    • 7.2 Spring的主要模块
    • 7.3 Spring中用到了哪些设计模式?
      • 7.3.1 单例模式
      • 7.3.2 代理模式
      • 7.3.3 模板方法
      • 7.3.4 观察者模式
      • 7.3.5 适配器模式
      • 7.3.6 装饰者模式
      • 7.3.7 总结
    • 7.4 描述一下Spring中Bean的生命周期?(常问)
    • 7.5 Spring 中的 bean 的作用域有哪些?
    • 7.6 Spring如何解决循环依赖问题?
    • 7.7 Spring事务实现原理
    • 7.8 SpringMVC 工作原理了解吗?(重要)
    • 7.9 @Component 和 @Bean 的区别是什么?
    • 7.10 将一个类声明为Spring的 bean 的注解有哪些?
    • 7.11 Spring 事务中的隔离级别有哪几种?
    • 7.12 Spring 事务中哪几种事务传播行为?
    • 7.13 @Transactional(rollbackFor = Exception.class)注解了解吗?
    • 7.14 AOP和IOC
      • 7.14.1 AOP
      • 7.14.2 IOC

7.1 Spring的6大特征

我们一直在用Spring,但是可能大部分同学对Spring的特征或者说他可以做哪些事情都还不清楚,我们先看一下Spring官网怎么描述,Spring 官网列出的 Spring 的 6 个特征:

  • 核心技术 :依赖注入(DI),AOP,事件(events),资源,i18n,验证,数据绑定,类型转换,SpEL。

  • 测试 :模拟对象,TestContext框架,Spring MVC 测试,WebTestClient。

  • 数据访问 :事务,DAO支持,JDBC,ORM,编组XML。

  • Web支持 : Spring MVC和Spring WebFlux Web框架。

  • 集成 :远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。

  • 语言 :Kotlin,Groovy,动态语言。

7.2 Spring的主要模块

  • Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC 依赖注入功能。

  • Spring Aspects :该模块为与AspectJ的集成提供支持。

  • Spring AOP :提供了面向切面的编程实现。

  • Spring JDBC : Java数据库连接。

  • Spring JMS :Java消息服务。

  • Spring ORM : 用于支持Hibernate等ORM工具。

  • Spring Web : 为创建Web应用程序提供支持。

  • Spring Test : 提供了对 JUnit 和 TestNG 测试的支持。

7.3 Spring中用到了哪些设计模式?

7.3.1 单例模式

在我们的系统中,有一些对象其实我们只需要一个,比如说:线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。

使用单例模式的好处:

  1. 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;

  2. 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。

Spring 中 bean 的默认作用域就是 singleton(单例)的。

spring依赖注入时,使用了双重判断加锁的单例模式

Spring 实现单例的方式

- xml:<bean id="userService" class="top.snailclimb.UserService" scope="singleton"/>- 注解:@Scope(value = "singleton")

Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式。

7.3.2 代理模式

AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:

7.3.3 模板方法

模板方法模式是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的实现方式。

public abstract class Template {//这是我们的模板方法public final void TemplateMethod(){PrimitiveOperation1();  PrimitiveOperation2();PrimitiveOperation3();}protected void  PrimitiveOperation1(){//当前类实现}//被子类实现的方法protected abstract void PrimitiveOperation2();protected abstract void PrimitiveOperation3();}
public class TemplateImpl extends Template {@Overridepublic void PrimitiveOperation2() {//当前类实现}@Overridepublic void PrimitiveOperation3() {//当前类实现}
}

Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。一般情况下,我们都是使用继承的方式来实现模板模式,但是 Spring 并没有使用这种方式,而是使用Callback 模式与模板方法模式配合,既达到了代码复用的效果,同时增加了灵活性。

7.3.4 观察者模式

观察者模式是一种对象行为型模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,这个对象所依赖的对象也会做出反应。Spring 事件驱动模型就是观察者模式很经典的一个应用。Spring 事件驱动模型非常有用,在很多场景都可以解耦我们的代码。比如我们每次添加商品的时候都需要重新更新商品索引,这个时候就可以利用观察者模式来解决这个问题。

Spring 事件驱动模型中的三种角色

  1. 事件角色: ApplicationEvent (org.springframework.context包下)充当事件的角色,这是一个抽象类,它继承了java.util.EventObject并实现了 java.io.Serializable接口。

Spring 中默认存在以下事件,他们都是对 ApplicationContextEvent 的实现(继承自ApplicationContextEvent):

  • ContextStartedEvent:ApplicationContext 启动后触发的事件;

  • ContextStoppedEvent:ApplicationContext 停止后触发的事件;

  • ContextRefreshedEvent:ApplicationContext 初始化或刷新完成后触发的事件;

  • ContextClosedEvent:ApplicationContext 关闭后触发的事件。

  1. 事件监听者角色:ApplicationListener 充当了事件监听者角色,它是一个接口,里面只定义了一个 onApplicationEvent()方法来处理ApplicationEvent。ApplicationListener接口类源码如下,可以看出接口定义看出接口中的事件只要实现了 ApplicationEvent就可以了。所以,在 Spring中我们只要实现 ApplicationListener 接口实现 onApplicationEvent() 方法即可完成监听事件

  2. 事件发布者角色:ApplicationEventPublisher 充当了事件的发布者,它也是一个接口。ApplicationEventPublisher 接口的publishEvent()这个方法在AbstractApplicationContext类中被实现,阅读这个方法的实现,你会发现实际上事件真正是通过ApplicationEventMulticaster来广播出去的

Spring 的事件流程总结

  1. 定义一个事件: 实现一个继承自 ApplicationEvent,并且写相应的构造函数;

  2. 定义一个事件监听者:实现 ApplicationListener 接口,重写 onApplicationEvent() 方法;

  3. 使用事件发布者发布消息: 可以通过 ApplicationEventPublisher 的 publishEvent() 方法发布消息。

// 定义一个事件,继承自ApplicationEvent并且写相应的构造函数
public class DemoEvent extends ApplicationEvent{private static final long serialVersionUID = 1L;private String message;public DemoEvent(Object source,String message){super(source);this.message = message;}public String getMessage() {return message;}// 定义一个事件监听者,实现ApplicationListener接口,重写 onApplicationEvent() 方法;
@Component
public class DemoListener implements ApplicationListener<DemoEvent>{//使用onApplicationEvent接收消息@Overridepublic void onApplicationEvent(DemoEvent event) {String msg = event.getMessage();System.out.println("接收到的信息是:"+msg);}}
// 发布事件,可以通过ApplicationEventPublisher  的 publishEvent() 方法发布消息。
@Component
public class DemoPublisher {@AutowiredApplicationContext applicationContext;public void publish(String message){//发布事件applicationContext.publishEvent(new DemoEvent(this, message));}
}

当调用 DemoPublisher 的 publish() 方法的时候,比如 demoPublisher.publish(“你好”) ,控制台就会打印出:接收到的信息是:你好 。

7.3.5 适配器模式

适配器模式(Adapter Pattern) 将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。

spring AOP中的适配器模式

我们知道 Spring AOP 的实现是基于代理模式,但是 Spring AOP 的增强或通知(Advice)使用到了适配器模式,与之相关的接口是AdvisorAdapter 。Advice 常用的类型有:BeforeAdvice(目标方法调用前,前置通知)、AfterAdvice(目标方法调用后,后置通知)、AfterReturningAdvice(目标方法执行结束后,return之前)等等。每个类型Advice(通知)都有对应的拦截器:MethodBeforeAdviceInterceptor、AfterReturningAdviceAdapter、AfterReturningAdviceInterceptor。Spring预定义的通知要通过对应的适配器,适配成 MethodInterceptor接口(方法拦截器)类型的对象(如:MethodBeforeAdviceInterceptor 负责适配 MethodBeforeAdvice)。

spring MVC中的适配器模式

在Spring MVC中,DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由HandlerAdapter 适配器处理。HandlerAdapter 作为期望接口,具体的适配器实现类用于对目标类进行适配,Controller 作为需要适配的类。

为什么要在 Spring MVC 中使用适配器模式? Spring MVC 中的 Controller 种类众多,不同类型的 Controller 通过不同的方法来对请求进行处理。如果不利用适配器模式的话,DispatcherServlet 直接获取对应类型的 Controller,需要的自行来判断,假如我们再增加一个 Controller类型就要在上面代码中再加入一行 判断语句,这种形式就使得程序难以维护,也违反了设计模式中的开闭原则 – 对扩展开放,对修改关闭。

7.3.6 装饰者模式

装饰者模式可以动态地给对象添加一些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。简单点儿说就是当我们需要修改原有的功能,但我们又不愿直接去修改原有的代码时,设计一个Decorator套在原有代码外面。其实在 JDK 中就有很多地方用到了装饰者模式,比如 InputStream家族,InputStream 类下有 FileInputStream (读取文件)、BufferedInputStream (增加缓存,使读取文件速度大大提升)等子类都在不修改InputStream 代码的情况下扩展了它的功能。

Spring 中配置 DataSource 的时候,DataSource 可能是不同的数据库和数据源。我们能否根据客户的需求在少修改原有类的代码下动态切换不同的数据源?这个时候就要用到装饰者模式(这一点我自己还没太理解具体原理)。Spring 中用到的包装器模式在类名上含有 Wrapper或者 Decorator。这些类基本上都是动态地给一个对象添加一些额外的职责。

7.3.7 总结

Spring 框架中用到了哪些设计模式:

  • 工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。

  • 代理设计模式 : Spring AOP 功能的实现。

  • 单例设计模式 : Spring 中的 Bean 默认都是单例的。

  • 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。

  • 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。

  • 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。

  • 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。

7.4 描述一下Spring中Bean的生命周期?(常问)

  1. Bean 容器找到配置文件中 Spring Bean 的定义。

  2. Bean 容器利用 Java Reflection API 创建一个Bean的实例。

  3. 如果涉及到一些属性值 利用 set()方法设置一些属性值。

  4. 如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean的名字。

  5. 如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。

  6. 如果Bean实现了 BeanFactoryAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoade r对象的实例。

  7. 与上面的类似,如果实现了其他 *.Aware接口,就调用相应的方法。

  8. 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法

  9. 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。

  10. 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。

  11. 如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法

  12. 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。

  13. 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

7.5 Spring 中的 bean 的作用域有哪些?

  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。

  • prototype : 每次请求都会创建一个新的 bean 实例。

  • request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。

  • session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。

  • global-session:全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

7.6 Spring如何解决循环依赖问题?

循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。

注意,这里不是函数的循环调用,是对象的相互依赖关系。循环调用其实就是一个死循环,除非有终结条件。

Spring中循环依赖场景有:

  1. 构造器的循环依赖
  2. field属性的循环依赖。

如何检测存在循环依赖:

检测循环依赖相对比较容易,Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明了循环依赖了。

Spring的循环依赖的理论依据其实是基于Java的引用传递,当我们获取到对象的引用时,对象的field或者属性是可以延后设置的(但是构造器必须是在获取引用之前)。
Spring的单例对象的初始化主要分为三步:

  1. createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象

  2. populateBean:填充属性,这一步主要是多bean的依赖属性进行填充

  3. initializeBean:调用spring xml中的init 方法。

从上面讲述的单例bean初始化步骤我们可以知道,循环依赖主要发生在第一、第二步。也就是构造器循环依赖和field循环依赖。

那么我们要解决循环引用也应该从初始化过程着手,对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存

这三级缓存分别指:

  • singletonFactories : 单例对象工厂的cache ----三级

  • earlySingletonObjects :提前暴光的单例对象的Cache ----二级

  • singletonObjects:单例对象的cache ----一级

我们在创建bean的时候,首先想到的是从cache中获取这个单例的bean,这个缓存就是singletonObjects。

需要解释两个参数:

  • isSingletonCurrentlyInCreation():判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)

  • allowEarlyReference:是否允许从singletonFactories中通过getObject拿到对象

分析getSingleton()的整个过程,Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,如果获取到了则:

  • this.earlySingletonObjects.put(beanName, singletonObject);
  • this.singletonFactories.remove(beanName);

从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存。从上面三级缓存的分析,我们可以知道,Spring解决循环依赖的诀窍就在于singletonFactories这个三级cache。

这里就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。

这样做有什么好处呢?让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。

知道了这个原理时候,肯定就知道为啥Spring不能解决“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。

缓存存放问题:

1.一级缓存:单例Bean

2.二级缓存:工厂,产生Bean

3.三级缓存:半成品Bean,只调用了构造函数

为什么需要三级缓存,一级缓存、二级缓存行不行?

只用一级缓存无法区分是半成品对象还是完整对象。用二级缓存一个可以存储半成品对象,一个可以存储完整对象,如果没有AOP,那么两级缓存也可以;但是现在加入了AOP,AOP使用动态代理(JDK或CGLIB),又多了一个代理对象,那么必须添加三级缓存,来区分是原始对象还是代理对象。

7.7 Spring事务实现原理

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:

  1. 获取连接 Connection con = DriverManager.getConnection()
  2. 开启事务con.setAutoCommit(true/false);
  3. 执行CRUD
  4. 提交事务/回滚事务 con.commit() / con.rollback();
  5. 关闭连接 conn.close();

使用Spring的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由Spirng 自动完成。

那么Spring是如何在我们书写的 CRUD 之前和之后开启事务和关闭事务的呢?

  1. 配置文件开启注解驱动,在相关的类和方法上通过注解@Transactional标识。
  2. spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,并且为这些类和方法生成代理,并根据@Transactional的相关参数进行相关配置注入,这样就在代理中为我们把相关的事务处理掉了(开启正常提交事务,异常回滚事务)。
  3. 真正的数据库层的事务提交和回滚是通过bin log或者redo log实现的。

事务的4个特性(ACID)

  1. 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。

  2. 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。

  3. 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

  4. 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

事务实现原理:

  1. 采用不同的连接器
  2. 用AOP新建立了一个链接;共享链接
  3. ThreadLocal当前事务
  4. 前提是关闭AutoCommit

7.8 SpringMVC 工作原理了解吗?(重要)

  1. 客户端(浏览器)发送请求,直接请求到 DispatcherServlet。

  2. DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。

  3. 解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。

  4. HandlerAdapter 会根据 Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。

  5. 处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。

  6. ViewResolver 会根据逻辑 View 查找实际的 View。

  7. DispaterServlet 把返回的 Model 传给 View(视图渲染)。

  8. 把 View 返回给请求者(浏览器)

7.9 @Component 和 @Bean 的区别是什么?

  1. 作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。

  2. @Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。

  3. @Bean 注解比 Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

7.10 将一个类声明为Spring的 bean 的注解有哪些?

我们一般使用 @Autowired 注解自动装配 bean,要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,采用以下注解可实现:

  1. @Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用@Component 注解标注。

  2. @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。

  3. @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。

  4. @Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

7.11 Spring 事务中的隔离级别有哪几种?

TransactionDefinition 接口中定义了五个表示隔离级别的常量

  1. TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.

  2. TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

  3. TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

  4. TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

  5. TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

7.12 Spring 事务中哪几种事务传播行为?

支持当前事务的情况:

  1. TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

  2. TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

  3. TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

不支持当前事务的情况:

  1. TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。

  2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。

  3. TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

其他情况:

  1. TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

7.13 @Transactional(rollbackFor = Exception.class)注解了解吗?

我们知道:Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。

当@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。

在@Transactional注解中如果不配置rollbackFor属性,那么事物只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚。

7.14 AOP和IOC

7.14.1 AOP

AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。

AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。

动态代理:AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。

1. JDK动态代理: 实现接口,java反射机制生成一个代理接口的匿名类,调用具体方法的时候调用invokeHandler。
2. CGlib:asm字节码编辑技术动态创建类 基于classLoad装载,修改字节码生成子类去处理。

静态代理和动态代理的比较

7.14.2 IOC

IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好IOC的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

  • 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IOC是有专门一个容器来创建这些对象,即由IOC容器来控制对 象的创建;谁控制谁?当然是IOC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

  • 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

简历上敢写自己熟练运用Spring,那这些问题你清楚嘛?相关推荐

  1. 面试官:只是了解的知识点简历上不要写熟悉,否则有你受的

    上周面试一位程序员,这位求职者给我留下了深刻印象. 这位求职者的简历有一项是这样写的,熟悉自定义View.他应聘的岗位是Android开发. "你在实际项目开发中有做过自定义View吗?&q ...

  2. java初级程序员简历上不能写,但是不能不会的项目!

    今天给大家讲讲找工作之前要练习写哪些项目,简历上的项目经验怎么写(初级程序员,没有工作过的实习生). 目录 一:练习哪些项目 二:简历上应该怎么写 一:练习哪些项目 1.J2SE记账本 本项目是基于S ...

  3. 先搞清楚这些问题,简历上再写你熟悉Java!

    原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 系列文章介绍 本文是<五分钟学Java>系列文章的一篇 本系列文章主要围绕Java程序员必须掌握的核心技能,结合我个人三年 ...

  4. 计算机男简历上可以写擅长各种游戏吗,简历中的计算机水平

    简历中的计算机水平 作为现代化办公系统,是离不开电脑的配合,所以如果你在电脑方面有专长,一定要在个人简历当中表现出来,这会增加你的印象分数.那么,如何才能够把简历中的计算机水平表达规范呢?下面跟小编来 ...

  5. 如果简历上真写了“会多线程”,那面试一般会被怎么问?

    最近,这条字节员工发布的朋友圈一夜刷爆网络,字节跳动大裁员的消息,引起了行业内的巨大震荡. 图片来源:网络 这次真的是不想跳槽也得跳槽了-,然后,竟然死在了上大学时候的一道题上,早知道大学好好学不泡妹 ...

  6. 你敢花一天时间看完本文在简历上添一笔“熟练使用C++编程”吗?

    基础 1 数据 1.1 常量.变量和helloworld的写法 #define day 7 const修饰变量 #include <iostream>using namespace std ...

  7. 为什么Java开发人员在简历上不敢轻易写精通Java

    你会Java语言进行开发,但是你敢说精通吗?但凡你简历上这么写,绝对会被人问到死. 技术深不只是停留在运用层面,更多的是对这门技术的使用场景,底层原理,遇到问题的处理方案,以及同类型的其他技术比较以及 ...

  8. 简历上面的项目经历怎么写?怎么写才能显得突出?

    项目经历可不可以是课堂项目? 其实对很多同学来说,不是不会写项目经历,而是根本不知道什么是项目经历,哪些内容可以写在项目经历中.所以看到简历中的项目经历模块,感觉不知道怎么写?那么对于大学生来说,即使 ...

  9. 跳槽面试,外包履历能写在简历上吗?

     外包的可怕之处在于心态. 如果你觉得自己没有归属感,每天按时上班,按时下班,做完工作就无所事事.这种工作状态,不管甲方还是乙方都是一个样子. 改变心态后,外包其实并没有想象中那么可怕,只要你有有能力 ...

最新文章

  1. spring-boot-starter-parent 作用
  2. 关于火狐3,怎么会这样??
  3. Linux 下的驱动开发最简单例子
  4. hdu 1281棋盘游戏(二分匹配)
  5. 自由软件不够吸引人?
  6. 爬虫入门【10】Pyspider框架简介及安装说明
  7. jquery实现网易云音乐的歌词展示部分
  8. 18年6月英语六级第一套听力单词
  9. 7-3 约分最简分式
  10. C语言编程>第二十七周 ① 请补充fun函数,该函数的功能是:寻找两个整数之间的所有素数(包括这两个整数),把结果保存在数组a中,函数返回素数的个数。
  11. 微信小程序腾讯服务器地址要购买吗,微信小程序JavaScript SDK
  12. 外贸:Facebook养号攻略
  13. [leetcode]Unique Paths II
  14. theano程序(一)
  15. 2038年危机!“Unix千年虫”
  16. 疫情期间远程办公,我这么计划
  17. 干货 | 如何在京东云上简单实践CI流程
  18. 高性能网络编程总结及《TCP/IP Sockets编程(C语言实现) (第2版)》 代码下载(链接以及文件打包)
  19. MATLAB 函数求极限,定积分,一阶导,二阶导(经典例题)
  20. 0、空字符和‘\0‘关系

热门文章

  1. Ubuntu下载中文输入法
  2. Bluetooth Profile Specification之(HFP篇)4.2 呼叫传输、设置、保持状态
  3. FIFO读rd写wr控制信号处理方式的简单理解-FPGA学习笔记(五)
  4. 正则表达式(C、C++、Python、Shell)
  5. Oracle 11gR2 新技术 Cardinality Feedback
  6. R 报错:参数不是数值也不是逻辑值:回覆NA--数据科学新类型tibble
  7. SPI速度最快,其次UART,IIC最慢。UART转成485通讯距离最长,其他两个应该差不多
  8. 教师计算机基础知识培训简报,信息技术能力提升培训简报.doc
  9. 提取DC综合report_constrain all violator中big neg slack
  10. JDBC 学习笔记1