为什么要使用 spring?

Spring 框架是一个轻量级的 Java 开发框架,它提供了一套全面的解决方案来简化企业级应用的开发。以下是使用 Spring 的几个主要原因:

  1. Inversion of Control (IoC): Spring 提供了 IoC 容器来管理对象的生命周期和依赖关系,这使得开发者能够更专注于业务逻辑而不是对象的创建和管理。

  2. Aspect-Oriented Programming (AOP): Spring 支持 AOP,可以帮助开发者更好地分离关注点,比如日志记录、事务管理和安全控制等。

  3. Transaction Management: Spring 提供了统一的事务管理接口,使得事务管理变得更加容易和一致。

  4. Data Access Abstraction: Spring 提供了一套抽象层来简化数据库访问,包括 JDBC、Hibernate 和 JPA 等。

  5. Web Framework: Spring MVC 提供了一个强大的模型-视图-控制器 (MVC) 框架,用于构建 Web 应用程序。

  6. Testability: Spring 使得应用程序更容易测试,因为它支持依赖注入,减少了对象间的耦合。

  7. Modularity: Spring 模块化的设计使得开发者可以选择使用框架中的某个部分而不必使用整个框架。

解释一下什么是 aop?

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在提高模块化程度,通过将横切关注点(cross-cutting concerns)从业务逻辑中分离出来。在传统的面向对象编程中,横切关注点通常散布在整个代码库中,比如日志记录、安全控制和事务管理等。AOP 允许开发者定义“切面”来封装这些横切关注点,并将它们应用到程序中的适当位置。

解释一下什么是 ioc?

控制反转(依赖注入),Spring容器中创建对象
IoC(Inversion of Control,控制反转)是一种设计原则,它提倡将对象的创建和管理权交给外部容器,而不是在对象内部自行管理依赖关系。在 Spring 中,IoC 容器负责管理对象的生命周期,并在需要的时候注入对象的依赖项。这种机制降低了组件之间的耦合,提高了代码的可重用性和可测试性。

Spring 有哪些主要模块?

Spring 框架由多个模块组成,其中一些核心模块包括:

  • Spring Core: 提供 IoC 容器的核心功能。

  • Spring Context: 构建于核心之上,提供了对资源访问的支持,例如消息国际化、事件发布、资源加载等。

  • Spring AOP: 支持面向切面编程。

  • Spring DAO: 数据访问抽象层,提供了异常处理等通用机制。

  • Spring ORM: 提供了对各种 ORM 框架(如 Hibernate, JPA, JDBC 等)的集成支持。

  • Spring Web: 提供了创建 Web 应用的基本支持。

  • Spring Web MVC: 提供了构建 Web 应用的 MVC 实现。

Spring 常用的注入方式有哪些?

Spring 支持多种依赖注入的方式,包括:

  • 构造器注入:通过构造器参数来注入依赖。

  • 设值注入(Setter Injection):通过 setter 方法注入依赖。

  • 字段注入:直接在字段上使用 @Autowired 注解来注入依赖。

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

Spring 容器本身并不保证 bean 的线程安全性。bean 的线程安全性取决于 bean 的实现方式。对于无状态的 bean(即不持有任何实例变量),它们通常是线程安全的。对于持有状态的 bean,开发者需要采取措施来保证线程安全,例如使用同步机制。

Spring 支持几种 bean 的作用域?

Spring 支持以下几种 bean 的作用域:

  • singleton: 默认作用域,表示一个 bean 定义在 Spring IoC 容器中只有一个实例。

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

  • request: 每个 HTTP 请求都会创建一个新的 bean 实例(仅限于 Web 应用)。

  • session: 每个 HTTP Session 都会创建一个新的 bean 实例(仅限于 Web 应用)。

  • global-session: 类似于 session 作用域,但在门户环境中使用(已废弃)。

Spring 自动装配 bean 有哪些方式?

Spring 支持以下几种自动装配的方式:

  • no: 不自动装配(默认)。

  • byName: 根据 bean 名称自动装配。

  • byType: 根据 bean 类型自动装配。

  • constructor: 使用构造器参数自动装配。

  • autodetect: 如果有单个构造器,则使用 constructor;否则使用 byType。

Spring 事务实现方式有哪些?

Spring 支持以下几种事务管理方式:

  • 编程式事务管理:通过编程的方式控制事务的开始、提交或回滚。

  • 声明式事务管理:通过配置或注解来管理事务,通常更为简洁。

说一下 Spring 的事务隔离?

Spring 支持以下几种事务隔离级别:

  • ISOLATION_DEFAULT: 使用数据库默认的隔离级别。

  • ISOLATION_READ_UNCOMMITTED: 读取未提交数据。

  • ISOLATION_READ_COMMITTED: 读取提交数据。

  • ISOLATION_REPEATABLE_READ: 重复读。

  • ISOLATION_SERIALIZABLE: 序列化。

说一下 Spring MVC运行流程?

Spring MVC 的运行流程大致如下:

  1. 客户端发送请求至前端控制器 DispatcherServlet

  2. DispatcherServlet 根据请求 URL 确定需要调用的 HandlerMapping

  3. HandlerMapping 根据请求找到合适的 Controller

  4. DispatcherServlet 调用相应的 Controller

  5. Controller 执行相应的业务逻辑并返回 ModelAndView

  6. ViewResolver 根据返回的 ModelAndView 选择合适的 View

  7. View 渲染返回给客户端

Spring MVC有哪些组件?

Spring MVC 主要组件包括:

  • DispatcherServlet: 前端控制器,处理所有的 HTTP 请求和响应。

  • HandlerMapping: 用于映射请求到对应的 Controller。

  • Controller: 处理请求并返回 Model 和 View 的名称。

  • ModelAndView: 包含模型数据和视图名称的对象。

  • ViewResolver: 用于解析视图名称并创建视图对象。

  • View: 渲染模型数据并返回给客户端。

  • HandlerAdapter: 用于处理特定类型的 Controller。

@RequestMapping 的作用是什么?

@RequestMapping 是一个用于映射 HTTP 请求到特定处理方法上的注解。它可以应用于类或方法级别,用于指定处理哪些 HTTP 请求。

@Autowired 的作用是什么?

@Autowired 是一个用于自动装配 bean 的注解。当 Spring 容器初始化时,它会自动将匹配的 bean 注入到标记了 @Autowired 的字段、构造器或方法中。这有助于减少显式的 setter 方法或构造器注入,使代码更加简洁。

在Spring框架中使用过事务吗,是怎么使用的?

在Spring框架中,事务管理是一项非常重要的功能,它可以帮助开发者更容易地管理和控制数据库操作中的事务边界。Spring提供了两种主要的方式来管理事务:编程式事务管理和声明式事务管理。

1. 编程式事务管理

编程式事务管理通过在代码中显式地使用PlatformTransactionManager接口来管理事务。这种方式适用于需要更细粒度控制事务的情况。

示例代码:
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class ExampleService {

    private final PlatformTransactionManager transactionManager;

    public ExampleService(DataSource dataSource) {
        this.transactionManager = new DataSourceTransactionManager(dataSource);
    }

    public void performAction() {
        TransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(def);

        try {
            // 执行业务逻辑
            someBusinessOperation();

            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }

    private void someBusinessOperation() {
        // 进行数据库操作
    }
}

2. 声明式事务管理

声明式事务管理通过配置注解@Transactional或XML配置来自动管理事务。这种方式更加简洁,不需要在每个方法中显式地管理事务,而是由Spring容器自动管理。

示例代码:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ExampleService {

    @Transactional
    public void performAction() {
        // 执行业务逻辑
        someBusinessOperation();
    }

    private void someBusinessOperation() {
        // 进行数据库操作
    }
}

配置事务管理器

无论采用哪种方式,都需要先配置事务管理器。如果是使用JDBC,则可以使用DataSourceTransactionManager;如果是使用JPA,则可以使用JpaTransactionManager

配置示例(基于Spring Boot):
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;

@Configuration
public class AppConfig {

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

关键点

  • 隔离级别:可以通过@Transactional注解的isolation属性来指定事务的隔离级别,默认为ISOLATION_DEFAULT

  • 传播行为:可以通过@Transactional注解的propagation属性来指定事务的传播行为,默认为PROPAGATION_REQUIRED

  • 只读事务:可以通过@Transactional注解的readOnly属性来标记事务是否只读,默认为false

  • 回滚规则:可以通过@Transactional注解的rollbackFor属性来指定在哪些异常下事务应该回滚。

注意事项

  • 在使用声明式事务管理时,确保目标类是通过代理创建的(例如通过@Component@Service等注解),这样Spring才能拦截方法并应用事务管理。

  • 如果类是自身调用自身的方法(即自我调用),那么事务管理不会生效,因为自我调用不会触发代理机制。可以通过@Transactional(proxyTargetClass = true)来开启CGLIB代理解决此问题。

  • 要注意异常处理,确保适当的异常类型被抛出以触发事务回滚。