Spring小结

Spring知识点小结


Spring?

  • Spring是一个开源框架,它由Rod Johnson创建,是为解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益

(1)目的:解决企业应用开发的复杂性

(2)功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能

(3)范围:任何Java应用

(4)简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架

(5)轻量: 从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类

6)控制反转: Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它

(7)面向切面: Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务()管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持

(8)容器: Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用

(9)框架: Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你,所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持

Spring 的两大特性是什么?

  • AOP(Aspect Oriented Programming,面向切面编程)与 IOC(Inverse of Control,控制反转
说说 Spring 的 AOP 的原理是什么?实现 AOP 有哪些方式?

Spring AOP 的底层使用的是动态代理,有两种实现方式:

  • JDK 动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 InvokeHandler 来处理

  • CGlib 动态代理:以 CGLIB(Code Generation Library)的方式进行代理,它采用底层字节码技术,将代理对象类的 class 文件加载进来,通过修改其字节码生成子类来处理

区别

  • JDK 代理只能对实现接口的类生成代理;CGLIB 是针对类实现代理,继承指定类并生成一个子类,因此不能代理 final 修饰的类
那么在 Spring 中,优先使用哪种 AOP 呢?
  • 如果目标对象实现了接口,默认会采用 JDK 的动态代理,但也可以强制使用 CGLIB

  • 如果目标对象没有实现接口,则必须采用 CGLIB 库

  • Spring 会自动在 JDK 动态代理和 CGLIB 之间转换

Spring 的 bean 的初始化及生命周期?

(1)实例化 Bean:

  • 对于 BeanFactory 容器,当向容器请求一个尚未初始化的 bean 时,或初始化 bean 的时候需要注入另一个尚未初始化 bean 的依赖时,容器就会调用 createBean 进行实例化

  • 对于 ApplicationContext 容器,当容器启动结束后,通过获取 BeanDefinition 对象中的信息,实例化所有的 bean

(2)设置对象属性(依赖注入):

  • 实例化后的 Bean 被封装在 BeanWrapper 对象中,然后 Spring 根据 BeanDefinition 中的信息以及通过 BeanWrapper 提供的设置属性的接口完成依赖注入

(3)处理 Aware 接口:

  • Spring 会检测该 Bean 是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给 Bean :
  1. 如果该 Bean 实现了 BeanNameAware 接口,会调用它实现的 setBeanName (String beanId) 方法,入参是 Spring 配置文件中 Bean 的 id 值
  2. 如果该 Bean 实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory () 方法,传递的是 Spring 工厂自身
  3. 如果该 Bean 已经实现了 ApplicationContextAware 接口,会调用 setApplicationContext (ApplicationContext) 方法,入参是 Spring 上下文

(4)处理 BeanPostProcessor 接口:

  • 如果该 Bean 实现了 BeanPostProcessor 接口,那将会调用 postProcessBeforeInitialization (Object obj, String s) 方法

(5)InitializingBean 与 init-method:

  • 如果该 Bean 在 xml 中配置了 init-method 属性,则会自动调用其配置的初始化方法。

  • 以上几个步骤完成后,Bean 就已经被正确创建了,之后就可以使用这个 Bean 了。

(6)处理 DisposableBean 接口:

  • 当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy () 方法

(7)处理 destroy-method 属性:

  • 最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法

Spring 支持的事务管理类型有哪些?各自的优缺点是什么

(1)编程式事务管理:是指在代码中手动的管理事务的提交、回滚等操作

(2)声明式事务管理:将事务管理作为一个 “切面” 代码单独编写,只用关心核心业务逻辑代码,然后通过 AOP 技术将事务管理的 “切面” 代码织入到业务类中

  • 声明式事务的缺点在于只能作用到方法级别,无法做到像编程式事务那样能控制到代码块级别;其优点则在于可以将业务代码和事务管理分离,编程式事务则对业务代码侵入式太强
  • Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的
对于纯 JDBC 操作数据库,想要用到事务,可以按照以下步骤进行:
  1. 获取连接 Connection con = DriverManager.getConnection ()
  2. 开启事务 con.setAutoCommit (true/false)
  3. 执行增删查改
  4. 提交事务 / 回滚事务 con.commit () /con.rollback ()
  5. 关闭连接 conn.close ()
  • 使用 Spring 的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由 Spirng 自动完成

  • 在编程式事务中,即通过编写代码实现事物管理,包括定义事务的开始,程序正常执行后的事物提交,异常时进行的事务回滚

  • 在声明式事务中,通过 AOP 功能来实现声明式事务处理的,具体操作(比如事务实行的配置和读取,事务对象的抽象),用 TransactionProxyFactoryBean 接口来使用 AOP 功能,生成 proxy 代理对象,通过 TransactionInterceptor 完成对代理方法的拦截,将事务处理的功能编织到拦截的方法中。说得更详细一点:

  1. Spring 事务处理模块是通过 AOP 功能为没有编写事务代码但加上了 @Transactional 注解的类生成代理
  2. 生成代理的过程中会读取 @Transactional 注解中的配置,比如传播行为、隔离级别、事务超时等
  3. 生成的代理会拦截目标对象的外部方法调用,自动开启事务、自动提交事务或回滚

Spring有哪些常用的 Context?

最常被使用的 ApplicationContext 接口实现:

  • FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径
  • ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件
  • WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的bean

Spring中如何使用注解来配置Bean?有哪些相关的注解?

首先需要在Spring配置文件中增加如下配置:

<context:component-scan base-package="org.example"/>

然后可以用@Component、@Controller、@Service、@Repository注解来标注需要由Spring IoC容器进行对象托管的类。这几个注解没有本质区别,只不过@Controller通常用于控制器,@Service通常用于业务逻辑类,@Repository通常用于存储类(DAO实现类),普通的类用@Component来标注

Spring的事务底层原理?

  1. 划分处理单元——IOC

    由于spring解决的问题是对单个数据库进行局部事务处理的,具体的实现首先用spring中的IOC划分了事务处理单元。并且将对事务的各种配置放到了IOC容器中(设置事务管理器,设置事务的传播特性及隔离机制)

  2. AOP拦截需要进行事务处理的类

    Spring事务处理模块是通过AOP功能来实现声明式事务处理的,具体操作(比如事务实行的配置和读取,事务对象的抽象),用TransactionProxyFactoryBean接口来使用AOP功能,生成proxy代理对象,通过TransactionInterceptor完成对代理方法的拦截,将事务处理的功能编织到拦截的方法中。读取ioc容器事务配置属性,转化为spring事务处理需要的内部数据结构(TransactionAttributeSourceAdvisor),转化为TransactionAttribute表示的数据对象

  3. 对事务处理实现(事务的生成、提交、回滚、挂起)

    spring委托给具体的事务处理器实现。实现了一个抽象和适配。适配的具体事务处理器:DataSource数据源支持、hibernate数据源事务处理支持、JDO数据源事务处理支持,JPA、JTA数据源事务处理支持。这些支持都是通过设计PlatformTransactionManager、AbstractPlatforTransaction一系列事务处理的支持。 为常用数据源支持提供了一系列的TransactionManager

  4. 结合

    PlatformTransactionManager实现了TransactionInterception接口,让其与TransactionProxyFactoryBean结合起来,形成一个Spring声明式事务处理的设计体系

@Transactional 失效?

  • @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常

  • 默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰

Spring框架中的单例bean是线程安全的吗?

  • 不,Spring框架中的单例bean不是线程安全的

Spring IOC容器配置Bean的方式?

  • 基于XML文件配置
  • 基于注解进行配置
  • 基于Java程序进行配置

Spring IOC的实现原理?

  • 工厂模式 + 反射机制

  • 加载配置文件,解析成 BeanDefinition 放在 Map 里

  • 调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法 —— 完成依赖注入

BeanFacotry 和 ApplicationContext有什么区别?

  • BeanFactory和 ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口

  • BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

    ①继承MessageSource,因此支持国际化

    ②统一的资源文件访问方式

    ③提供在监听器中注册bean的事件

    ④同时加载多个配置文件

    ⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

  • 创建Bean的时机不一样:

    BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常

    ②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了

    ③相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢

  • BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader

  • BeanFactory和 ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册

如何理解AOP中的连接点(Joinpoint)、切入点(Pointcut)、增强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)、目标对象(Target)、代理对象(Proxy)这些概念?

连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但Spring只支持方法级的连接点

切入点(Pointcut):如果连接点相当于数据中的记录,那么切入点相当于查询条件,一个切入点可以匹配多个连接点。Spring AOP的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。

增强(Advice):是切面的具体实现。以目标方法为参照点,根据放置的地方不同,可分为前置增加(Before)、后置增加(After Returning)、异常增加(After Throwing)、最终增加(After)与环绕增加(Around)5种。在实际应用中通常是切面类中的一个方法,具体属于哪类增加,同样是在配置中指定的。

说明: Advice在国内的很多书面资料中都被翻译成"通知",但是很显然这个翻译无法表达其本质,有少量的读物上将这个词翻译为"增强",这个翻译是对Advice较为准确的诠释,我们通过AOP将横切关注功能加到原有的业务逻辑上,这就是对原有业务逻辑的一种增强。

引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。

织入(Weaving):织入是将增强添加到目标类具体连接点上的过程,AOP有三种织入方式:①编译期织入:需要特殊的Java编译期(例如AspectJ的ajc);②装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;③运行时织入:在运行时为目标类生成代理实现增强。Spring采用了动态代理的方式实现了运行时织入,而AspectJ采用了编译期织入和装载期织入的方式。

切面(Aspect):其实就是共有功能的实现。如日志切面、权限切面、事务切面等。在实际应用中通常是一个存放共有功能实现的普通Java类,之所以能被AOP容器识别成切面,是在配置中指定的。

目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。这些对象中已经只剩下干干净净的核心业务逻辑代码了,所有的共有功能代码等待AOP容器的切入。

代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物


69道Spring面试题和答案

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值