7a4519db6509b743692fd9a3d900be2.png 1、使用Spring框架的好处是什么?

  1. 轻量:Spring 是轻量的,基本的版本大约2MB;
  2. 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们;
  3. 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开
  4. 容器:Spring 包含并管理应用中对象的生命周期和配置;
  5. MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品;
  6. 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA);
  7. 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出 的)转化为一致的unchecked 异常。

    2、什么是 Spring IOC 容器?

    IoC(Inversion of Control)是控制反转的意思,这是一种面向对象编程的设计思想。在不采用这种思想的情况下,我们需要自己维护对象与对象之间的依赖关系,很容易造成对象之间的耦合度过高,在一个大型的项目中这十分的不利于代码的维护。IoC则可以解决这种问题,它可以帮我们维护对象与对象之间的依赖关系,降低对象之间的耦合度。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入(DI)来管理组成应用程序的组件。容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或 Java 代码提供。

    说到 IoC 就不得不说DI(Dependency Injection)DI是依赖注入的意思它是IoC实现的实现方式,就是说IoC是通过DI来实现的。由于 IoC 这个词汇比较抽象而 DI 却更直观,所以很多时候我们就用 DI 来代替它,在很多时候我们简单地将 IoC 和 DI 划等号,这是一种习惯。而实现依赖注入的关键是 IoC 容器,它的本质就是一个工厂。

3、什么是依赖注入?可以通过多少种方式完成依赖注入?

在依赖注入中,您不必创建对象,但必须描述如何创建它们。您不是直接在代码中将组件和服务连接在一起,而是描述配置文件中哪些组件需要哪些服务。IoC 容器将它们装配在一起。通常,依赖注入可以通过三种方式完成,即:

  1. 构造函数注入:就是被注入对象可以在它的构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。然后,IoC Service Provider 会检查被注入的对象的构造方法,取得它所需要的依赖对象列表,进而为其注入相应的对象。构造方法注入方式比较直观,对象被构造完成后,即进入就绪状态,可以马上使用。
  2. setter 注入:通过 setter 方法,可以更改相应的对象属性。所以,当前对象只要为其依赖对象所对应的属性添加 setter 方法,就可以通过 setter 方法将相应的依赖对象设置到被注入对象中。setter 方法注入虽不像构造方法注入那样,让对象构造完成后即可使用,但相对来说更宽松一些,可以在对象构造完成后再注入。
  3. 接口注入:相对于前两种注入方式来说,接口注入没有那么简单明了。被注入对象如果想要 IoC Service Provider 为其注入依赖对象,就必须实现某个接口。这个接口提供一个方法,用来为其注入依赖对象。IoC Service Provider 最终通过这些接口来了解应该为被注入对象注入什么依赖对象。相对于前两种依赖注入方式,接口注入比较死板和烦琐。

image.png

4、BeanFactory 和 ApplicationContext?

Spring主要提供了两种类型的容器:BeanFactory 和 ApplicationContext。
BeanFactory 是一个类工厂,与传统类工厂不同的是,BeanFactory 是类的通用工厂,它可以创建并管理各种类的对象。这些可被创建和管理的对象本身没有什么特别之处,仅是一个POJO,Spring称这些被创建和管理的Java对象为Bean。并且,Spring中所说的Bean比JavaBean更为宽泛一些,所有可以被Spring容器实例化并管理的Java类都可以成为Bean。
BeanFactory 是 Spring 容器的顶层接口Spring 为 BeanFactory 提供了多种实现,最常用的是XmlBeanFactory。但它在 Spring 3.2 中已被废弃,建议使用 XmlBeanDefinitionReader、DefaultListableBeanFactory 替代。BeanFactory最主要的方法就是 getBean(String beanName),该方法从容器中返回特定名称的Bean。
BeanFactory:是基础类型的 IoC 容器,提供完整的 IoC 服务支持。如果没有特殊指定,默认采用延迟初始化策略。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。对于资源有限,并且功能要求不是很严格的场景,BeanFactory 是比较合适的IoC容器选择。
ApplicationContext:它是在 BeanFactory 的基础上构建的,是相对比较高级的容器实现除了拥有BeanFactory 的所有支持,ApplicationContext 还提供了其他高级特性,比如事件发布、国际化信息支持等。ApplicationContext 所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容器启动时间较之 BeanFactory 也会长一些。在那些系统资源充足,并且要求更多功能的场景中,ApplicationContext类型的容器是比较合适的选择。

BeanFactory ApplicationContext
懒加载 即时加载
使用显式语法提供资源对象 自己创建和管理资源对象
不支持国际化 支持国际化
不支持基于依赖的注解 支持依赖的注解

BeanFactory的优缺点:

  • 优点:应用启动的时候占用资源很少,对资源要求较高的应用,比较有优势;
  • 缺点:运行速度会相对来说慢一些。而且有可能会出现空指针异常的错误,而且通过 Bean 工厂创建的 Bean生命周期会简单一些。

ApplicationContext的优缺点:

  • 优点:所有的 Bean 在启动的时候都进行了加载,系统运行的速度快;在系统启动的时候,可以发现系统中的配置问题。
  • 缺点:把费时的操作放到系统启动中完成,所有的对象都可以预加载,缺点就是内存占用较大。

    5、Spring 提供了哪些配置方式?

    基于 xml 配置: bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签开头。例如:
    1. <bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
    2. <property name="name" value="Edureka"></property>
    3. </bean>
    基于注解配置: 您可以通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用 XML 来 描述 bean 装配。默认情况下,Spring 容器中未打开注解装配。因此,您需要在使用它之前在 Spring 配 置文件中启用它。例如:
    1. <beans>
    2. <context:annotation-config/>
    3. <!-- bean definitions go here -->
    4. </beans>
    基于 Java API 配置: Spring 的 Java 配置是通过使用 @Bean@Configuration 来实现。
  1. @Bean 注解扮演与元素相同的角色。
  2. @Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。

例如:

  1. @Configuration
  2. public class StudentConfig {
  3. @Bean
  4. public StudentBean myStudent() {
  5. return new StudentBean();
  6. }
  7. }

6、Spring 是如何管理 Bean 的?

Spring 通过 IoC 容器来管理 Bean,我们可以通过 XML 配置或者注解配置,来指导 IoC 容器对 Bean 的管理。因为注解配置比 XML 配置方便很多,所以现在大多时候会使用注解配置的方式。
以下是管理Bean时常用的一些注解:

  1. @ComponentScan 用于声明扫描策略,通过它的声明,容器就知道要扫描哪些包下带有声明的类,也可以知道哪些特定的类是被排除在外的。
  2. @Component、@Repository、@Service、@Controller 用于声明 Bean,它们的作用一样,但是语义不同。@Componen t用于声明通用的 Bean,@Repository 用于声明 DAO 层的 Bean,@Service 用于声明业务层的 Bean,@Controller 用于声明视图层的控制器 Bean,被这些注解声明的类就可以被容器扫描并创建。
  3. @Autowired、@Qualifier 用于注入 Bean,即告诉容器应该为当前属性注入哪个 Bean。其中,@Autowired 是按照 Bean 的类型进行匹配的,如果这个属性的类型具有多个 Bean,就可以通过@Qualifier 指定 Bean 的名称,以消除歧义。
  4. @Scope 用于声明 Bean 的作用域,默认情况下 Bean 是单例的,即在整个容器中这个类型只有一个实例。可以通过 @Scope 注解指定 prototype 值将其声明为多例的,也可以将 Bean 声明为 session 级作用域、request 级作用域等等,但最常用的还是默认的单例模式。
  5. @PostConstruct、@PreDestroy 用于声明 Bean 的生命周期。其中,被 @PostConstruct 修饰的方法将在 Bean 实例化后被调用,@PreDestroy 修饰的方法将在容器销毁前被调用。

    7、Spring 中的 bean 的作用域有哪些? Spring支持集中bean scope?

    默认情况下,Bean 在 Spring 容器中是单例的,我们可以通过 @Scope 注解修改 Bean 的作用域。该注解有如下5个取值,它们代表了 Bean 的5种不同类型的作用域:
类型 说明
singleton 在 Spring 容器中仅存在一个实例,即 Bean 以单例的形式存在。
prototype 每次调用 getBean() 时,都会执行 new 操作,返回一个新的实例。
request 每次 HTTP 请求都会创建一个新的 Bean。
session 同一个 HTTP Session 共享一个 Bean,不同的 HTTP Session 使用不同的Bean。
globalSession 同一个全局的 Session 共享一个 Bean,一般用于Portlet环境。

8、说一说 Bean的生命周期?

面试题:Spring Bean的生命周期
主要把握创建过程和销毁过程这两个大的方面;
创建过程:

  • 首先实例化 Bean,并设置Bean的属性;
  • 根据其实现的 Aware 接口(主要是 BeanFactoryAware接口,BeanFactoryAware,ApplicationContextAware)设置依赖信息
  • 接下来调用 BeanPostProcess 的 postProcessBeforeInitialization方法完成initial前的自定义逻辑;afterPropertiesSet 方法做一些属性被设定后的自定义的事情;
  • 调用Bean自身定义的init方法,去做一些初始化相关的工作;然后再调用 postProcessAfterInitialization 去做一些bean初始化之后的自定义工作。
  • 此时,Bean 初始化完成,可以使用这个 Bean 了。

销毁过程:如果实现了DisposableBean的destroy方法,则调用它,如果实现了自定义的销毁方法,则调用之。

9、Spring是怎么解决循环依赖的?

Spring中的循环依赖

10、什么是 spring 的内部 bean?

只有将 bean 用作另一个 bean 的属性时,才能将 bean 声明为内部 bean。为了定义bean,Spring 的基于 XML 的配置元数据在 中提供了 元素的使用。内部 bean 总是匿名的,它们总是作为原型。
例如,假设我们有一个 Student 类,其中引用了 Person 类。这里我们将只创建一个 Person 类实例并在 Student 中使用它。

  1. public class Student {
  2. private Person person;
  3. //Setters and Getters
  4. }
  5. public class Person {
  6. private String name;
  7. private String address;
  8. //Setters and Getters
  9. }
  1. <bean id=“StudentBean" class="com.edureka.Student">
  2. <property name="person">
  3. <!--This is inner bean -->
  4. <bean class="com.edureka.Person">
  5. <property name="name" value="Scott"></property>
  6. <property name="address" value="Bangalore"></property>
  7. </bean>
  8. </property>
  9. </bean>

11、@Autowired 和 @Resource 注解有什么区别?

@Autowired @Resource
Spring提供的注解 JDK提供的注解
只能按类型注入,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它 required 属性为false,如果我们想使用按名称装配,可以结合@Qualifier 注解一起使用。 默认按名称注入,也支持按类型注入。
@Resource有两个中重要的属性:name和type。name 属性指定 byName,如果没有指定 name 属性,当注解标注在字段上,即默认取字段的名称作为bean 名称寻找依赖对象,当注解标注在属性的 setter方法上,即默认取属性名作为 bean 名称寻找依赖对象。
需要注意的是,@Resource 如果没有指定 name 属性,并且按照默认的名称仍然找不到依赖对象时, @Resource 注解会回退到按类型装配。但一旦指定了name 属性,就只能按名称装配了。

12、@RequestMapping 注解有什么用?

@RequestMapping 注解用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。此注释可应用于两个级别:

  • 类级别:映射请求的 URL
  • 方法级别:映射 URL 以及 HTTP 请求方法

    13、列举 spring 支持的事务管理类型

    Spring 支持两种类型的事务管理:
  1. 程序化事务管理:在此过程中,在编程的帮助下管理事务。它为您提供极大的灵活性,但维护起来非常困难。
  2. 声明式事务管理:在此,事务管理与业务代码分离。仅使用注解或基于 XML 的配置来管理事务。

image.png

14、Spring的事务如何配置,常用注解有哪些?

事务的打开、回滚和提交是由事务管理器来完成的,我们使用不同的数据库访问框架,就要使用与之对应的事务管理器。在Spring Boot中,当你添加了数据库访问框架的起步依赖时,它就会进行自动配置,即自动实例化正确的事务管理器。
对于声明式事务,是使用 「@Transactional」 进行标注的。这个注解可以标注在类或者方法上。

  • 当它标注在类上时,代表这个类所有公共(public)非静态的方法都将启用事务功能。
  • 当它标注在方法上时,代表这个方法将启用事务功能。

另外,在@Transactional注解上,我们可以使用 isolation 属性声明事务的隔离级别,使用 propagation 属性声明事务的传播机制。

15、说一说你对声明式事务的理解

Spring事务管理的亮点在于声明式事务管理,它允许我们通过声明的方式,在 IoC 配置中指定事务的边界和事务属性,Spring会自动在指定的事务边界上应用事务属性。相对于编程式事务来说,这种方式十分的方便,只需要在需要做事务管理的方法上,增加 @Transactional 注解,以声明事务特征即可。

16、Spring 中默认提供的单例是线程安全的吗?

不是。当多个用户同时请求一个服务时,容器会给每一个请求分配一个线程,这时多个线程会并发执行该请求对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对单例状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。 线程安全问题都是由全局变量及静态变量引起的。 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑「线程同步」,否则就可能影响线程安全.。
Spring容器本身并没有提供Bean的线程安全策略。
如果单例的Bean是一个无状态的Bean,即线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例的Bean是线程安全的。比如,Controller、Service、DAO这样的组件,通常都是单例且线程安全的。
如果单例的Bean是一个有状态的Bean,则可以采用「ThreadLocal」对状态数据做线程隔离,来保证线程安全。

17、什么是 AOP?

AOP(Aspect Oriented Programming)是面向切面编程,它是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。如下图,可以很形象地看出,所谓切面,相当于应用对象间的横切点,我们可以将其单独抽象为单独的模块。
image.png
AOP可以有多种实现方式,而Spring AOP支持如下两种实现方式。

  • JDK动态代理:这是Java提供的动态代理技术,可以在运行时创建接口的代理实例。Spring AOP默认采用这种方式,在接口的代理实例中织入代码。通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口 。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类 。
  • CGLib动态代理:采用底层的字节码技术,在运行时创建子类代理的实例。当目标对象不存在接口时,Spring AOP 就会采用这种方式,在子类实例中织入代码。CGLIB ( Code Generation Library ),是一个代码生成的类库,可以在运行 时动态的生成某个类的子类,注意, CGLIB 是通过继承的方式做的动态代理,因此如果某个 类被标记为 final ,那么它是无法使用 CGLIB 做动态代理的。

AOP的术语:

  • 连接点(join point):对应的是具体被拦截的对象,因为 Spring 只能支持方法,所以被拦截的对象往往就是指特定的方法,AOP 将通过动态代理技术把它织入对应的流程中。
  • 切点(point cut):有时候,我们的切面不单单应用于单个方法,也可能是多个类的不同方法,这时,可以通过正则式和指示器的规则去定义,从而适配连接点。切点就是提供这样一个功能的概念。
  • 通知(advice):就是按照约定的流程下的方法,分为前置通知、后置通知、环绕通知、事后返回通知和异常通知,它会根据约定织入流程中。
  • 目标对象(target):即被代理对象。
  • 引入(introduction):是指引入新的类和其方法,增强现有 Bean 的功能。
  • 织入(weaving):它是一个通过动态代理技术,为原有服务对象生成代理对象,然后将与切点定义匹配的连接点拦截,并按约定将各类通知织入约定流程的过程。
  • 切面(aspect):是一个可以定义切点、各类通知和引入的内容,SpringAOP 将通过它的信息来增强Bean 的功能或者将对应的方法织入流程。

image.png
image.png

18、请你说说AOP的应用场景

Spring AOP 为 IoC 的使用提供了更多的便利,一方面,应用可以直接使用 AOP 的功能,设计应用的横切关注点,把跨越应用程序多个模块的功能抽象出来,并通过简单的 AOP 的使用,灵活地编制到模块中,比如可以通过AOP 实现应用程序中的日志功能。另一方面,在 Spring 内部,一些支持模块也是通过 Spring AOP 来实现的,比如事务处理。从这两个角度就已经可以看到 Spring AOP 的核心地位了。

19、Spring Bean的生命周期?

面试题:Spring Bean的生命周期

20、Spring Framework 中有多少个模块,它们分别是什么?

Spring - 图8
Spring 核心容器 – 该层基本上是 Spring Framework 的核心。它包含以下模块:

  • Spring Core · Spring Bean · SpEL (Spring Expression Language)
  • Spring Context

数据访问/集成 – 该层提供与数据库交互的支持。它包含以下模块:

  • JDBC (Java DataBase Connectivity)
  • ORM (Object Relational Mapping)
  • OXM (Object XML Mappers) · JMS (Java Messaging Service)
  • Transaction

Web – 该层提供了创建 Web 应用程序的支持。它包含以下模块:

  • Web
  • Web – Servlet
  • Web – Socket
  • Web – Portlet

AOP

  • 该层支持面向切面编程

Instrumentation

  • 该层为类检测和类加载器实现提供支持。

Test - 该层为使用 JUnit 和 TestNG 进行测试提供支持。

21、Spring 应用程序有哪些不同组件?

Spring 应用一般有以下组件:

  • 接口 - 定义功能。
  • Bean 类 - 它包含属性,setter 和 getter 方法,函数等。
  • Spring 面向切面编程(AOP) - 提供面向切面编程的功能。
  • Bean 配置文件 - 包含类的信息以及如何配置它们。
  • 用户程序 - 它使用接口。