目录
三 .简述Spring中如何基于注解配置Bean和装配Bean
四. 说出Spring 或者 Springmvc中常用的5个注解,并解释含义
八. 请解释@Autowired注解的工作机制及required属性的作用
九. 简述Spring声明式事务中@Transaction中常用的两种事务传播行为
十四 .Spring 支持的事务管理类型有哪些?你在项目中使用哪种方式?怎么理解全局事务和局部事务?
十五 @Resources 和@Autowired 的区别?
一 .Spring的两大核心是什么?谈一谈你对IOC的理解? 谈一谈你对DI的理解? 谈一谈你对 AOP 的理解?(必会)
三 Spring 支持 bean 的作用域有几种吗? 每种作用域是什么样的?(必会)
四 BeanFactory 和 ApplicationContext 有什么区别(了解)
七 你知道的 Spring 的通知类型有哪些,分别在什么时候执行?(了解)
八 Spring 的对象默认是单例的还是多例的? 单例 bean 存不存在线程安全问
九 @Resource 和@Autowired 依赖注入的区别是什么? @Qualifier 使用场
十 一 BeanFactory和ApplicationContext的区别?
硅谷
一 .请写出 spring 中常用的依赖注入方式。
通过 setter 方法注入
通过构造方法注入
二 .简述Spring中IOC容器常用的接口和具体的实现类
- BeanFactory SpringIOC容器的基本设置,是最底层的实现, 面向框架本身的.
- ApplicationContext BeanFactory的子接口, 提供了更多高级的特定. 面向开发者的.
- ConfigurableApplicationContext, ApplicationContext的子接口,扩展出了 close 和 refresh等 关闭 刷新容器的方法
- ClassPathXmlApplicationContext:从classpath的XML配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。
- FileSystemXmlApplicationContext :由文件系统中的XML配置文件读取上下文。
- XmlWebApplicationContext:由Web应用的XML文件读取上下文。
三 .简述Spring中如何基于注解配置Bean和装配Bean
(1)首先要在Spring中配置开启注解扫描
<context:component-scan base-package=” ”></ context:component-scan> |
(2)在具体的类上加上具体的注解
(3)Spring 中通常使用@Autowired 或者是@Resource 等注解进行bean的装配
四. 说出Spring 或者 Springmvc中常用的5个注解,并解释含义
@Component 基本注解,标识一个受Spring管理的组件
@Controller 标识为一个表示层的组件
@Service 标识为一个业务层的组件
@Repository 标识为一个持久层的组件
@Autowired 自动装配
@Qualifier(“”) 具体指定要装配的组件的id值
@RequestMapping() 完成请求映射
@PathVariable 映射请求URL中占位符到请求处理方法的形参
五.请解释Spring Bean的生命周期?
(1)默认情况下,IOC容器中bean的生命周期分为五个阶段:
- 调用构造器 或者是通过工厂的方式创建Bean对象
- 给bean对象的属性注入值
- 调用初始化方法,进行初始化, 初始化方法是通过init-method来指定的.
- 使用
- IOC容器关闭时, 销毁Bean对象.
(2)当加入了Bean的后置处理器后,IOC容器中bean的生命周期分为七个阶段:
- 调用构造器 或者是通过工厂的方式创建Bean对象
- 给bean对象的属性注入值
- 执行Bean后置处理器中的 postProcessBeforeInitialization
- 调用初始化方法,进行初始化, 初始化方法是通过init-method来指定的.
- 执行Bean的后置处理器中 postProcessAfterInitialization
- 使用
- IOC容器关闭时, 销毁Bean对象
六.简述Spring 中bean的作用域
总共有四种作用域:
- Singleton 单例的
- Prototype 原型的
- Request
- Session
七. 简述Spring中自动装配常用的两种装配模式
byName: 根据bean对象的属性名进行装配
byType: 根据bean对象的属性的类型进行装配,需要注意匹配到多个兼容类型的bean对象时,会抛出异常。
八. 请解释@Autowired注解的工作机制及required属性的作用
(1)首先会使用byType的方式进行自动装配,如果能唯一匹配,则装配成功,
如果匹配到多个兼容类型的bean, 还会尝试使用byName的方式进行唯一确定.
如果能唯一确定,则装配成功,如果不能唯一确定,则装配失败,抛出异常.
(2)默认情况下, 使用@Autowired标注的属性必须被装配,如果装配不了,也会抛出异常.
可以使用required=false来设置不是必须要被装配.
九. 简述Spring声明式事务中@Transaction中常用的两种事务传播行为
通过propagation来执行事务的传播行为
REQUIRED:使用调用者的事务,如果调用者没有事务,则启动新的事务运行
REQUIRES_NEW:将调用者的事务挂起,开启新的事务运行。
十. 简述Spring中切面中常用的几种通知,并简单解释
前置通知 在目标方法执行之前执行
后置通知 在目标方法执行之后执行,不管目标方法有没有抛出异常
返回通知 在目标方法成功返回之后执行, 可以获取到目标方法的返回值
异常通知 在目标方法抛出异常后执行
环绕通知 环绕着目标方法执行
十一 .谈谈你对Spring 的理解
Spring 是一个开源框架,为简化企业级应用开发而生。Spring 可以是使简单的JavaBean 实现以前只有EJB 才能实现的功能。Spring 是一个 IOC 和 AOP 容器框架。
Spring 容器的主要核心是:
控制反转(IOC),传统的 java 开发模式中,当需要一个对象时,我们会自己使用 new 或者 getInstance 等直接或者间接调用构造方法创建一个对象。而在 spring 开发模式中,spring 容器使用了工厂模式为我们创建了所需要的对象,不需要我们自己创建了,直接调用spring 提供的对象就可以了,这是控制反转的思想。
依赖注入(DI),spring 使用 javaBean 对象的 set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程,就是依赖注入的思想。
面向切面编程(AOP),在面向对象编程(oop)思想中,我们将事物纵向抽成一个个的对象。而在面向切面编程中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。AOP 底层是动态代理,如果是接口采用 JDK 动态代理,如果是类采用CGLIB 方式实现动态代理。
十二 Spring中常用的设计模式
(1)代理模式——spring 中两种代理方式,若目标对象实现了若干接口,spring 使用jdk 的java.lang.reflect.Proxy类代理。若目标兑现没有实现任何接口,spring 使用 CGLIB 库生成目标类的子类。
(2)单例模式——在 spring 的配置文件中设置 bean 默认为单例模式。
(3)模板方式模式——用来解决代码重复的问题。
比如:RestTemplate、JmsTemplate、JpaTemplate
(4)工厂模式——在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用同一个接口来指向新创建的对象。Spring 中使用 beanFactory 来创建对象的实例。
十三 请描述一下Spring的事务管理
(1)声明式事务管理的定义:用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。这样的好处是,事务管理不侵入开发的组件,具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可,这样维护起来极其方便。
基于 TransactionInterceptor 的声明式事务管理:两个次要的属性: transactionManager,用来指定一个事务治理器, 并将具体事务相关的操作请托给它; 其他一个是 Properties 类型的transactionAttributes 属性,该属性的每一个键值对中,键指定的是方法名,方法名可以行使通配符, 而值就是表现呼应方法的所运用的事务属性。
(2)基于 @Transactional 的声明式事务管理:Spring 2.x 还引入了基于 Annotation 的体式格式,具体次要触及@Transactional 标注。@Transactional 可以浸染于接口、接口方法、类和类方法上。算作用于类上时,该类的一切public 方法将都具有该类型的事务属性。
(3)编程式事物管理的定义:在代码中显式挪用 beginTransaction()、commit()、rollback()等事务治理相关的方法, 这就是编程式事务管理。Spring 对事物的编程式管理有基于底层 API 的编程式管理和基于 TransactionTemplate 的编程式事务管理两种方式。
十四 .Spring 支持的事务管理类型有哪些?你在项目中使用哪种方式?怎么理解全局事务和局部事务?
Spring支持编程式事务管理和声明式事务管理。Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。
事务分为全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器JTA支持(如WebLogic、WildFly等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用Connetion对象来操作事务;而采用Hibernate进行持久化时,需要使用Session对象来操作事务。
这些事务的父接口都是PlatformTransactionManager。Spring的事务管理机制是一种典型的策略模式,PlatformTransactionManager代表事务管理接口,该接口定义了三个方法,该接口并不知道底层如何管理事务,但是它的实现类必须提供getTransaction()方法(开启事务)、commit()方法(提交事务)、rollback()方法(回滚事务)的多态实现,这样就可以用不同的实现类代表不同的事务管理策略。使用JTA全局事务策略时,需要底层应用服务器支持,而不同的应用服务器所提供的JTA全局事务可能存在细节上的差异,因此实际配置全局事务管理器是可能需要使用JtaTransactionManager的子类,如:WebLogicJtaTransactionManager(Oracle的WebLogic服务器提供)、UowJtaTransactionManager(IBM的WebSphere服务器提供)等。
十五 .Spring循环依赖问题
常见问法
请解释一下spring中的三级缓存
三级缓存分别是什么?三个Map有什么异同?
什么是循环依赖?请你谈谈?看过spring源码吗?
如何检测是否存在循环依赖?实际开发中见过循环依赖的异常吗?
多例的情况下,循环依赖问题为什么无法解决?
什么是循环依赖?
两种注入方式对循环依赖的影响?
官方解释
相关概念
实例化:堆内存中申请空间
初始化:对象属性赋值
三级缓存
四个关键方法
package org.springframework.beans.factory.support;
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/**
单例对象的缓存:bean名称—bean实例,即:所谓的单例池。
表示已经经历了完整生命周期的Bean对象
第一级缓存
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
早期的单例对象的高速缓存: bean名称—bean实例。
表示 Bean的生命周期还没走完(Bean的属性还未填充)就把这个 Bean存入该缓存中也就是实例化但未初始化的 bean放入该缓存里
第二级缓存
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**
单例工厂的高速缓存:bean名称—ObjectFactory
表示存放生成 bean的工厂
第三级缓存
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}
debug源代码过程
需要22个断点(可选)
1,A创建过程中需要B,于是A将自己放到三级缓里面,去实例化B
2,B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A
3,B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)
然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A自己放到一级缓存里面。
总结
1,Spring创建 bean主要分为两个步骤,创建原始bean对象,接着去填充对象属性和初始化。
2,每次创建 bean之前,我们都会从缓存中查下有没有该bean,因为是单例,只能有一个。
3,当创建 A的原始对象后,并把它放到三级缓存中,接下来就该填充对象属性了,这时候发现依赖了B,接着就又去创建B,同样的流程,创建完B填充属性时又发现它依赖了A又是同样的流程,不同的是:这时候可以在三级缓存中查到刚放进去的原始对象A。
所以不需要继续创建,用它注入 B,完成 B的创建既然 B创建好了,所以 A就可以完成填充属性的步骤了,接着执行剩下的逻辑,闭环完成
Spring解决循环依赖依靠的是Bean的"中间态"这个概念,而这个中间态指的是已经实例化但还没初始化的状态—>半成品。实例化的过程又是通过构造器创建的,如果A还没创建好出来怎么可能提前曝光,所以构造器的循环依赖无法解决
其他衍生问题
问题1:为什么构造器注入属性无法解决循环依赖问题?
由于spring中的bean的创建过程为先实例化 再初始化(在进行对象实例化的过程中不必赋值)将实例化好的对象暴露出去,供其他对象调用,然而使用构造器注入,必须要使用构造器完成对象的初始化的操作,就会陷入死循环的状态
问题2:一级缓存能不能解决循环依赖问题? 不能
在三个级别的缓存中存储的对象是有区别的 一级缓存为完全实例化且初始化的对象 二级缓存实例化但未初始化对象 如果只有一级缓存,如果是并发操作下,就有可能取到实例化但未初始化的对象,就会出现问题
问题3:二级缓存能不能解决循环依赖问题?
理论上二级缓存可以解决循环依赖问题,但是需要注意,为什么需要在三级缓存中存储匿名内部类(ObjectFactory),原因在于 需要创建代理对象 eg:现有A类,需要生成代理对象 A是否需要进行实例化(需要) 在三级缓存中存放的是生成具体对象的一个匿名内部类,该类可能是代理类也可能是普通的对象,而使用三级缓存可以保证无论是否需要是代理对象,都可以保证使用的是同一个对象,而不会出现,一会儿使用普通bean 一会儿使用代理类
黑马
一 .谈谈你对 Spring 的理解?
二 . IOC 是什么?
三 IOC 原理
四 IOC 的使用场景?
五 IOC 中 Bean 有几种注入方式?
六 SpringBean 自动装配的几种方式?
七 AOP 是什么?
八 AOP 主要用在哪些场景中?
九 SpringBean 的作用域有几种
十 Spring 事务管理方式?
十一 Spring 事务传播行为有几种?
十二 Spring 中的事务隔离级别?
十三 Spring 中的设计模式有哪些?
十四 Spring 的常用注解有哪些?(重要)
十五 @Resources 和@Autowired 的区别?
以下为重点记忆
黑马
一 .Spring的两大核心是什么?谈一谈你对IOC的理解? 谈一谈你对DI的理解? 谈一谈你对 AOP 的理解?(必会)
二 .Spring 的生命周期?(高薪常问)
三 Spring 支持 bean 的作用域有几种吗? 每种作用域是什么样的?(必会)
四 BeanFactory 和 ApplicationContext 有什么区别(了解)
五 Spring 框架中都用到了哪些设计模式?(必会)
六 Spring 事务的实现方式和实现原理(必会)
七 你知道的 Spring 的通知类型有哪些,分别在什么时候执行?(了解)
八 Spring 的对象默认是单例的还是多例的? 单例 bean 存不存在线程安全问
题呢?(必会)
九 @Resource 和@Autowired 依赖注入的区别是什么? @Qualifier 使用场
景是什么?(了解)
十 Spring 的常用注解(必会) 非常重要
十一 Spring 的事务传播行为(高薪常问)
十二 Spring 中的隔离级别 (高薪常问)
动力节点2021
一 . 什么是 Spring 框架?
Spring 是一种轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性。
我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是:核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。比如:核心容器中的 Core 组件是Spring 所有组件的核心,Beans 组件和 Context 组件是实现IOC和依赖注入的基础,AOP组件用来实现面向切面编程。
二 列举一些重要的Spring模块?
Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC 依赖注入功能。
Spring AOP :提供了面向切面的编程实现。
Spring JDBC : Java数据库连接。
Spring JMS :Java消息服务。
Spring ORM : 用于支持Hibernate等ORM工具。
Spring Web : 为创建Web应用程序提供支持。
Spring Test : 提供了对 JUnit 和 TestNG 测试的支持。
三 Spring 中的设计模式
工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
四 什么是Ioc及其优点
IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。
在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。
五 IOC容器的初始化过程
IOC容器的初始化主要包括Resource定位,载入和注册三个步骤,接下来我们依次介绍。
Resource资源定位:
Resouce定位是指BeanDefinition的资源定位,也就是IOC容器找数据的过程。Spring中使用外部资源来描述一个Bean对象,IOC容器第一步就是需要定位Resource外部资源。由ResourceLoader通过统一的Resource接口来完成定位。
BeanDefinition的载入:
载入过程就是把定义好的Bean表示成IOC容器内部的数据结构,即BeanDefinition。在配置文件中每一个Bean都对应着一个BeanDefinition对象。
通过BeanDefinitionReader读取,解析Resource定位的资源,将用户定义好的Bean表示成IOC容器的内部数据结构BeanDefinition。
在IOC容器内部维护着一个BeanDefinitionMap的数据结构,通过BeanDefinitionMap,IOC容器可以对Bean进行更好的管理。
BeanDefinition的注册:
注册是将前面的BeanDefition保存到Map中的过程,通过BeanDefinitionRegistry接口来实现注册。
六 Spring 提供了多种依赖注入的方式
Set 注入
构造器注入
接口注入
注解注入
Spring启动时读取应用程序提供的Bean 配置信息,并在Spring 容器中生成一份相应的Bean 配置注册表,然后根据这张注册表实例化Bean,装配好Bean 之间的依赖关系,为上层应用提供准备就绪的运行环境。其中Bean 缓存池为HashMap 实现
七 Spring中,如何给对象的属性赋值?
1. 通过构造函数
2. 通过set方法给属性注入值
3. 自动装配
byName 通过参数名自动装配,如果一个bean的name 和另外一个bean的 property 相同就自动装配。
byType 通过参数的数据类型自动自动装配,如果一个bean的数据类型和另 外一个bean的property属性的数据类型兼容,就自动装配必须确保 该类型在IOC容器中只有一个对象;否则报错。
4.注解
使用注解步骤:
1)先引入context名称空间
xmlns:context="http://www.springframework.org/schema/context"
2)开启注解扫描
<context:component-scan base-package="cn.itcast.e_anno2"></context:component-scan>
3)使用注解
通过注解的方式,把对象加入ioc容器。
创建对象以及处理对象依赖关系,相关的注解:
@Component 指定把一个对象加入IOC容器
@Repository 作用同@Component; 在持久层使用
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
@Resource或@Autowired 属性注入
@Qualifier指定注入bean的名称,防止在容器中有重名的bean
总结:
1) 使用注解,可以简化配置,且可以把对象加入IOC容器,及处理依赖关系(DI)
2) 注解可以和XML配置一起使用。3) @Resource的作用相当于@Autowired,只不过@Autowired按byType自动 注入,而 @Resource默认按 byName自动注入
八 bean对象创建的细节
1) 对象创建: 单例/多例
scope="singleton", 默认值, 即 默认是单例 【service/dao/工具类】
scope="prototype", 多例; 【Action对象】
Spring的单例bean不是线程安全的(可以用局部变量使线程安全)
2) 什么时候创建?
scope="prototype" 在用到对象的时候,才创建对象。
scope="singleton" 在启动(容器初始化之前), 就已经创建了bean,且整个应用只有一个。
3)是否延迟创建
lazy-init="false" 默认为false, 不延迟创建,即在启动时候就创建对象
lazy-init="true" 延迟初始化, 在用到对象的时候才创建对象(只对单例有效)
4) 创建对象之后,初始化/销毁
init-method="init_user" 【对应对象的init_user方法,对象创建之后执行】 destroy-method="destroy_user" 【在调用容器对象的destriy方法时候执行,(容器用实现类)】
九 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 都 有不同的会话
十 Bean的生命周期
Bean 容器找到配置文件中 Spring Bean 的定义。
Bean 容器利用 Java Reflection API 创建一个Bean的实例。
如果涉及到一些属性值利用 set()方法设置一些属性值。
如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean的名字。
如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
与上面的类似,如果实现了其他 *.Aware接口,就调用相应的方法。
如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法
如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法
当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。
十 一 BeanFactory和ApplicationContext的区别?
BeanFactory是Spring里面最顶层的接口,包含了各种Bean的定义,读取Bean配置文档,管理Bean的加载、实例化,控制Bean的生命周期,维护Bean之间的依赖关系。
ApplicationContext接口是BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能
十二 AOP
答: AOP,面向切面编程是指当需要在某一个方法之前或者之后做一些额外的操作,比如说日志记录,权限判断,异常统计等,可以利用AOP将功能代码从业务逻辑代码中分离出来。
Spring中的AOP主要有两种实现方式:
使用JDK动态代理实现,使用java.lang.reflection.Proxy类来处理
使用cglib来实现
两种实现方式的不同之处:
JDK动态代理,只能对实现了接口的类生成代理,而不是针对类,该目标类型实现的接口都将被代理。原理是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。
cglib主要针对类实现代理,对是否实现接口无要求。原理是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以被代理的类或方法不可以声明为final类型。
Spring AOP对这两种代理方式的选择:
如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP,也可以强制使用cglib实现AOP;
如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换。
十三 事务
Spring支持编程式事务(不用)和声明式事务两种方式:
编程式事务管理:使用TransactionTemplate实现。
声明式事务管理:建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务的优点:
就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。
事务选择:
声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足之处是声明式事务的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。
当多个Spring事务存在的时候,Spring定义了下边的7个传播行为来处理这些事务行为:
PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
spring事务对于查询的find()是只读,对保存save()是读写?