SPRING

150 阅读15分钟

什么是是spring,有什么作用?

一个开源的、轻量级的企业级应用开发框架,用于简化开发。支持IOC、AOP。可以很方便的访问数据库, 很方便的集成任务、缓存、邮件等第三方组件、支持单元测试、支持RestFul Java应用程序的开发。

作用:简化开发、提高可维护性、提高可测试性、提高性能。

spring的核心模块?

  • Spring Core:提供了Spring框架的基本组件,包括IoC容器、BeanFactory、资源加载等。
  • Spring Context:基于Spring Core,提供了更加丰富的上下文支持。比如提供IOC容器、 提供AOP支持、统一的配置管理、事件机制、国际化支持、web应用开发支持。
// 创建一个Spring Context
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 从Spring Context中获取一个bean对象
UserService userService = context.getBean(UserService.class);

// 使用bean对象进行业务操作
User user = userService.getUserById(1);
user.setName("new name");
userService.updateUser(user);
  • Spring AOP:提供了面向切面编程的支持,可以将横切关注点与业务逻辑进行分离。
  • Spring JDBC:提供了对JDBC的封装和简化,使开发者更简单的使用JDBC进行数据库操作。
  • Spring ORM:提供了对ORM框架的支持,包括Hibernate、MyBatis等。
  • Spring Web:提供了对Web应用的支持,包括MVC、WebSocket、REST等。
  • Spring Test:Spring框架的测试模块,提供了JUnit和TestNG的集成支持,可以帮助开发者实现单元测试和集成测试。

springioc

什么是ioc

ioc是一种思想,叫做控制反转。它得核心思想是把对象的管理权限交给容器。应用程序如果需要使用某个对象的实例,直接在IOC容器中获取就可以了,这种设计的好处在于降低了程序里面对象和对象之间的耦合度,使得程序的整个体系结 构变的更加灵活。

Bean的声明方式

在xml里面通过标签或者通过@service等注解声明,或者通过@Configuration配置类里面通过@bean注解去声明等,spring在启动的时候回去解析这些bean,然后保存到IOC容器里面。 # IOC的工作流程 IOC容器的初始化阶段,根据程序里面定义的XML或者注解等Bean的声明方式通过解析和加载后生成BeanDefinition,然后把BeanDefinition注册到IOC容器里面。通过注解或者XML声明的bean都会解析得到一个BeanDefinition实体,这个实体里面会包含Bean的一些定义和基本的一些属性,最后把这个BeanDefinition保存到一个Map集合里面,完成一个IOC的初始化。 IOC的作用就是对这些bean的定义信息进行处理和维护,它是IOC容器控制和反转的一个核心。第二个阶段是完成bean的依赖注入和初始化,通过反射去对没有设置@lazy-init属性的单例bean进行初始化,第二个是完成bean的依赖注入,最后就是bean的使用。通常通过@Autoware这样的一个注解或者通过BeanFactory.getBean()从IOC容器中获取一个bean,另外对于设置了@lazy-init以及非单例是在每次获取bean对象的时候,调用bean的初始化方法来完成示例化的,并且spring容器不会去管理这些bean。

spring中的依赖注入?实现方式有哪些?

依赖注入(Dependency Injection,简称DI)是Spring框架的核心特性之一,它是一种通过容器管理组件之间依赖关系的方式。依赖注入的实现方式包括:

  • 构造函数注入:通过构造函数将依赖关系注入到组件中。
  • Setter方法注入:通过Setter方法将依赖关系注入到组件中。
  • 接口注入:通过接口将依赖关系注入到组件中。

AOP是什么?作用?

AOP(面向切面编程)是Spring框架的另一个核心特性,它可以将横切关注点(如日志、事务、安全等)与业务逻辑进行分离,提高了代码的可维护性和可重用性。AOP实现方式包括:

  • 基于注解:通过注解的方式定义切面和切点。
  • 基于XML配置:通过XML配置文件定义切面和切点。

spring的事务?实现方式?

Spring框架提供了对事务管理的支持,可以帮助开发者更加轻松地管理事务。事务管理的实现方式包括:

  • 基于注解:通过注解的方式定义事务的边界和传播行为。
  • 基于XML配置:通过XML配置文件定义事务的边界和传播行为。

事务失效的场景

方法返回的是另一个方法由于是目标对象调用而不是代理对象调用导致失效

如果事务出现RuntimeException及其子类,事务会回滚,但如果在try-catch中捕获,会失效

多线程

不同的数据源

方法调用,被调用的方法没有加@Transaction注解

设置为读取未提交隔离级别

在事务中调用了另一个对象的方法,该对象没有被spring容器管理

在事务中使用了数据库锁导致事务失效

事务超时

数据库异常

springmvc模块?主要作用是什么?

Spring框架中的MVC模块是一个基于模型-视图-控制器(Model-View-Controller,简称MVC)的Web框架,它可以帮助开发者更加轻松地实现Web应用。MVC模块的主要作用包括:

  • 分离关注点:将应用的不同部分分离开来,使得代码更加易于维护和修改。
  • 提供灵活性:MVC框架提供了灵活的配置和扩展方式,可以根据实际需求进行自定义。
  • 支持RESTful风格:MVC框架支持RESTful风格的Web服务开发,可以帮助开发者更加轻松地实现Web API。

springbean的生命周期?

Spring框架中的Bean生命周期包括以下几个阶段:

  • 实例化:当Spring容器接收到配置文件中定义的Bean后,会通过反射机制创建Bean的实例。
  • 属性赋值:通过Setter方法将属性值赋给Bean。
  • BeanPostProcessor:可实现该接口在Bean初始化前后进行处理,例如初始化前后对Bean进行一些修改。可用作AOP生成代理对象、属性注入、事件监听、事务管理等
  • 初始化:Bean的初始化方法,可通过实现InitializingBean接口或在配置文件中指定初始化方法。
  • 销毁:调用Bean的销毁方法,可通过实现DisposableBean接口或在配置文件中指定销毁方法。

springbean的作用域?以及作用?

Spring框架中的Bean作用域包括以下几种:

  • singleton:单例模式,每个Bean容器中只有一个实例,默认是单例模式。
  • prototype:原型模式,每次请求都会创建一个新的实例。即调用getBean()
  • request:请求模式,每次HTTP请求都会创建一个新的实例。适用于在请求期间使用的bean
  • session:会话模式,每次HTTP会话都会创建一个新的实例。
  • global session:全局会话模式,一般用于基于portlet的Web应用,每个portlet应用都共享一个全局会话。一般是在用户登录应用时创建,在用户退出或超时时销毁。在配置时,需要指定一个唯一的会话id,以便于在多个请求之间识别和共享同一个会话。

spring中的配置方式?

Spring框架中的配置方式包括:

  • 基于XML配置:XML配置文件描述Bean之间的依赖关系,比较灵活,但是配置文件较为繁琐。
  • 基于注解配置:通过注解描述Bean之间的依赖关系,比XML配置更加简洁,但是可读性较差。
  • 基于Java配置:通过Java代码描述Bean之间的依赖关系,比XML配置更加简洁,可读性较好,但是需要编写大量的Java代码。

10. Spring Boot是什么,它的主要作用是什么?

Spring Boot是Spring框架的一个子项目,它可以帮助开发者更加轻松地快速构建Spring应用。Spring Boot的主要作用包括:

  • 简化配置:Spring Boot提供了一系列的自动配置和约定优于配置的功能,可以帮助开发者更加轻松地进行配置。
  • 快速开发:Spring Boot提供了一系列的快速开发工具和组件,可以帮助开发者更加轻松地进行开发。
  • 易于部署:Spring Boot提供了一系列的部署工具和支持,可以帮助开发者更加轻松地进行部署。

springboot自动装配?

在项目启动类上一般有@SpringBootApplication注解

该注解包括@SpringBootConfiguration/@EnableAutoConfiguration/@ComponenScan

第一个注解说明该类是一个配置类,第三个注解用于指定spring容器扫描路径需要加载的bean

重点是第二个注解:

作用为:

自动配置类由pom文件中的各个starter提供,使用@Configuration+@Bean定义配置类,并且放到MATEINFO/spring.factories下

使用Spring spi机制扫描MATEINFO/spring.factories下的配置类

使用@Import导入自动配置类

什么是spring的spi机制

Spring SPI机制是Spring框架中的一种扩展机制,通过该机制,用户可以为Spring框架提供自定义的扩展实现。SPI全称为Service Provider Interface,即服务提供者接口。在Spring中,SPI机制是通过Java标准的ServiceLoader实现的。用户只需要在classpath下编写实现了指定接口的类,并在META-INF/services目录下创建以接口全限定名为名称的文件,文件中列出实现类的全限定名即可。Spring框架在初始化时会自动加载这些实现类,并将其注入到相应的扩展点中。通过SPI机制,用户可以自定义实现一些Spring框架的扩展点,例如BeanPostProcessor、BeanFactoryPostProcessor等。

为什么一般的springboot项目没有classpath文件

在Spring Boot项目中,一般不需要手动创建classpath文件或META-INF/services目录,因为Spring Boot提供了自动配置机制,可以自动扫描classpath下的所有类,并根据类的注解和配置信息自动配置Spring应用程序上下文中的各种组件。

具体来说,Spring Boot会自动扫描classpath下的所有META-INF/spring.factories文件,并根据文件中列出的实现类自动配置各种组件,例如自动配置类、自动配置的Bean、自动配置的过滤器、自动配置的拦截器等。

因此,在Spring Boot项目中,我们只需要编写相关的实现类,并在类中添加相应的注解或配置信息,就可以实现自动配置,无需手动创建classpath文件或META-INF/services目录

spring 为什么被设计为不可变?

@Autowired 和 @Resource 的区别是什么?

@Autowired` 是 Spring 提供的注解,@Resource是 JDK 提供的注解。

@Autowired默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。

当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。

Spring中Bean的生命周期

生命周期是指:Bean在Spring(IOC)中从创建到销毁的整个过程。

分为:

1、实例化:为Bean分配内存空间;

2、设置属性:将当前类依赖的Bean属性,进行注入和装配。

3、初始化:

执行各种通知,执行初始化的前置方法,

执行初始化方法,执行初始化的后置方法。

4、使用Bean:在程序中使用Bean对象

5、销毁Bean:将Bean对象进行销毁操作。

ps:值得注意的是:实例化和初始化是两个完全不同的过程。实例化只是给Bean分配了内存空间,而初始化则是将程序的执行权从系统级别转换到用户级别,比开始执行用户添加的业务代码。

Spring中的循环依赖及解决

在Spring中,循环依赖是指两个或多个bean之间相互依赖,形成一个循环的依赖关系。这种情况下,Spring容器无法正确地创建这些bean,会抛出BeanCurrentlyInCreationException异常。

为了解决循环依赖问题,Spring采用了三级缓存的方式:

  1. 一级缓存:singletonObjects,用于存储已经创建好的单例对象。
  2. 二级缓存:earlySingletonObjects,用于存储正在创建中的单例对象。
  3. 三级缓存:singletonFactories,用于存储用于创建单例对象的工厂类。

当Spring创建一个bean时,首先会检查一级缓存中是否已经存在该bean的实例,如果存在,则直接返回该实例;如果不存在,则进入二级缓存中查找是否存在正在创建中的实例,如果存在,则返回该实例的代理对象;如果也不存在,则进入三级缓存中查找是否存在用于创建该bean的工厂类,如果存在,则使用该工厂类创建实例,并将实例存储到二级缓存中,最后返回该实例的代理对象。

如果在创建bean的过程中发现循环依赖的情况,Spring会通过提前暴露当前正在创建的bean,解决循环依赖问题。即将正在创建的bean放入二级缓存中,并将其提前暴露,供其他bean使用,以解决循环依赖问题。

需要注意的是,循环依赖只有在同一个ApplicationContext中才会出现,因为不同的ApplicationContext拥有不同的BeanFactory,所以不存在循环依赖的问题。

spring中的bean都是单例的吗?什么情况下不是?

在Spring中,默认情况下,所有的bean都是单例的,即在容器启动时就被创建,且只创建一次,之后每次请求都返回同一个实例。

但是,Spring也支持创建非单例的bean,即在每次请求时都创建一个新的实例。创建非单例的bean需要在bean的定义中设置scope属性,常用的scope有:

  1. singleton(默认):单例,即在容器启动时创建,之后每次请求都返回同一个实例。
  2. prototype:原型,即每次bean请求都创建一个新的实例。
  3. request:请求,即在一个HTTP请求中创建一个实例,该实例在整个请求期间都可用。
  4. session:会话,即在一个HTTP会话中创建一个实例,该实例在整个会话期间都可用。
  5. websocket:在websocket的生命周期中复用一个单例对象。

除了以上常用的scope,还有其他一些较少使用的scope,例如:global session、application等。

需要注意的是,非单例的bean需要考虑线程安全的问题,因为每次请求都会创建一个新的实例,可能会导致并发问题。因此,在设计非单例的bean时,需要考虑其线程安全性。

spring中的bean是线程安全的吗?

在Spring中,单例的bean默认情况下是线程安全的,因为在容器启动时就被创建,且只创建一次,之后每次请求都返回同一个实例。

非单例的Bean则不一定是线程安全的,因为每次请求都会创建一个新的实例,可能会导致并发问题。

除此之外,Spring中还有一些特殊的作用域,例如请求作用域和会话作用域。请求作用域的Bean在一次HTTP请求中创建一个实例,该实例在整个请求期间都可用。会话作用域的Bean在一个HTTP会话中创建一个实例,该实例在整个会话期间都可用。这些作用域的Bean需要考虑并发问题,因为它们可能会被多个线程同时访问。

因此,跟Bean的作用域没有关系对于如果Bean是无状态的,则是线程安全的,如果是有状态的,则不一定是线程安全的。对于任意作用域的Bean,是不是线程安全还是要看这个Bean本身。但是不同作用域的Bean需要考虑不同的线程安全问题。

spring中的依赖注入。

Spring中的依赖注入(Dependency Injection,DI)是一种设计模式,它允许对象相互解耦,从而增强了代码的灵活性、可维护性和可测试性。

在Spring中,依赖注入是通过容器来实现的。容器负责创建对象并将它们相互连接起来,从而形成一个完整的应用程序。当一个对象需要另一个对象时,它不再通过自己创建或查找依赖项,而是通过容器来获取依赖项。

依赖注入可以分为三种方式:构造函数注入、Setter方法注入和字段注入。其中,构造函数注入是最常用的方式,它允许我们在创建对象时直接注入依赖项。Setter方法注入是通过设置对象的属性来注入依赖项,而字段注入则是直接将依赖项注入到对象的字段中。

Spring中的依赖注入有以下优点:

1、减少代码的耦合性,提高代码的重用性和可维护性;

2、支持AOP等高级功能,可以更加方便地实现事务管理、日志记录等功能。

总之,依赖注入是Spring框架的核心特性之一,它大大简化了应用程序的开发和维护,提高了代码的质量和可测试性。