banner
NEWS LETTER

springboot

Scroll down

Cookie, Session, Token, JWT区别

RequestBody和RequestParam和PathVariable

@RequestParam:从?拼接中获取参数

@RequestBody:从请求体中json格式获取参数

@PathVariable:从url中获取参数

Autowired和Resource区别

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
  • Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
  • 当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。
  • @Autowired 支持在构造函数、方法、字段和参数上使用。@Resource 主要用于字段和方法上的注入,不支持在构造函数或参数上使用。

@PostContruct和@PreDestory

@PostConstruct:在Bean加载前执行的逻辑

@PreDestory:在Bean被销毁前执行的逻辑

0. SpringBoot自动装配原理?

@SpringBootApplication有三个核心注解:

  • @EnableAutoConfiguration:启用SpringBoot的自动配置机制
  • @Configuration:允许在上下文中注册额外的bean或导入其他配置类
  • @ComponentScan:扫描被@Component(@Service、@Controller)注解的bean

![image-20250304131016053](/Users/effy/Library/Application Support/typora-user-images/image-20250304131016053.png)

![image-20240719141859555](/Users/effy/Library/Application Support/typora-user-images/image-20240719141859555.png)

Spring如何解决循环依赖

三级缓存

Bean的生命周期

Spring和Spring Boot框架的优势分别是什么?

Spring:

  • **依赖注入(DI)和控制反转(IoC)**:通过依赖注入和控制反转机制,Spring允许将对象的创建和依赖关系管理从应用程序代码中分离出来,交给Spring容器处理使得代码更加模块化、可维护,降低组建之间的耦合度,提高代码的复用性。例如,一个业务逻辑类需要依赖一个数据访问层的接口,在 Spring 中可以通过配置或注解的方式将数据访问层的实现类注入到业务逻辑类中,而不需要在业务逻辑类中直接实例化数据访问层对象。
  • **面向切面编程(AOP)**:Spring支持面向切面编程(AOP),允许将横切关注点(如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,以切面的形式进行统一处理。这样可以使业务逻辑代码更加清晰、简洁,提高了代码的可读性和可维护性。比如,可以通过 AOP 切面来统一记录所有业务方法的执行日志,而不需要在每个业务方法中都编写重复的日志记录代码。
  • 丰富的框架集成:Spring 提供了与各种其他框架(如 Hibernate、MyBatis、Struts 等)的良好集成支持。它可以轻松地与这些框架协同工作,整合不同框架的优势,构建功能强大的企业级应用。例如,在一个 Web 应用中,可以使用 Spring 与 Hibernate 集成来实现数据持久化,与 Struts 集成来处理 Web 请求和视图展示。

SpringBoot:

  • 快速构建项目:Spring Boot 提供了大量的自动配置功能,能够根据项目的依赖和配置自动配置 Spring 应用的各种组件,大大减少了项目的配置工作量,提高了开发效率。开发者只需关注业务逻辑的实现,而无需花费大量时间在繁琐的配置上。例如,只需在项目中添加 Spring Boot 的 Web 依赖,就可以快速创建一个可以运行的 Web 应用,无需手动配置 Tomcat 服务器等相关组件。
  • 内置服务器:Spring Boot 内置了如 Tomcat 等服务器,应用可以直接以可执行的 JAR 或 WAR 包的形式运行,不需要像传统的 Java Web 应用那样部署到外部服务器上。这简化了应用的部署过程,方便了开发、测试和部署环节,提高了项目的可移植性和灵活性。比如,可以通过命令行直接运行 Spring Boot 应用的 JAR 包,启动内置的服务器来提供服务。
  • 监控与管理:Spring Boot Actuator 提供了对应用的监控和管理功能,能够方便地查看应用的运行状态、性能指标、健康状况等信息。还可以通过 HTTP 端点或 JMX 等方式对应用进行监控和管理,为运维和故障排查提供了有力的支持。例如,可以通过访问特定的 HTTP 端点获取应用的内存使用情况、线程信息、数据库连接池状态等。

@Transactional

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = CustomException.class, isolation = Isolation.READ_COMMITTED)


public class PaymentFailedException extends Exception {
// ...
}

// 在事务方法中配置
@Transactional
public void processPayment() throws PaymentFailedException {
// 业务逻辑
...
paymentService.update().setSql("money = money - 100").eq("user_id", userId).gt("money", 0).update();

throw new PaymentFailedException();

paymentService.update().setSql("money = money - 100").eq("user_id", userId).gt("money", 0).update();

}
  • propagation:事务的传播行为

  • rollbackFor:指定触发事务回滚的异常类型,

    • 默认行为:默认只有RuntimeException和Error会触发事务回滚,其子类异常也会触发回滚

    • 当需要让CheckedException也触发回滚时,需要显示配置

  • isolation: Spring事务的隔离等级,默认为Isolation.DEFAULT,即使用数据库的隔离等级

Spring事务失效的场景

方法内部调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public Result seckillVoucher(Long voucherId) {
...
Long userId = UserHolder.getUSer().getId();
synchronized (userId.toString().intern()) {
return createVoucherOrder(voucherId);
}
}

@Transactional
public Result createVoucherOrder(Long voucherId) {
...
return Result.ok();
}

@Transaction是通过AOP实现的。在调用seckillVoucher()方法的时候,该方法并没有获取到事务的功能,在调用createVoucherOrder()的时候,其实是this.createVoucherOrder(),这时候的this并不是代理对象代理之后的方法,也就不会再拥有事务的功能。方法内部调用导致事务失效的解决方法共有三种。

方法一:添加一个Service方法

方法二:在Service类中注入自己

方法三:通过AopContent类,在该Service类中使用AopContent.currentProxy()获取代理对象

1
IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();

访问权限不正确

private方法导致事务失效

1
2
3
4
5
@Transactional
private Result createVoucherOrder(Long voucherId) {
...
return Result.ok();
}

方法使用final修饰

因为通过cglib是通过生成子类的方式生成代理类,如果方法被定义为final,则该方法无法被重写,也就无法添加事务功能。

1
2
3
4
5
@Transactional
public final Result createVoucherOrder(Long voucherId) {
...
return Result.ok();
}

未被Spring管理

Spring在依赖查找时,从BeanFactory中取出需要被代理的类,即事务生效的前提是对象要被Spring管理,可以使用@Service、@Component、@Repository实现Bean的依赖注入

1
2
3
4
5
6
7
8
9
//@Service
public class UserService {

@Transactional
public void add(UserModel userModel) {
saveData(userModel);
updateData(userModel);
}
}

多线程调用

事务不能跨线程使用,这是因为insertUser()方法和doOtherThing()方法在不同的线程中,那么它们获取到的数据库连接也是不一样的,这就导致,这两个方法在不同的事务中。这一点可以在org.springframework.transaction.support.TransactionSynchronizationManager中得到印证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Slf4j
@Service
public class UserService {

@Autowired
private UserMapper userMapper;
@Autowired
private RoleService roleService;

@Transactional
public void add(UserModel userModel) throws Exception {
userMapper.insertUser(userModel);
new Thread(() -> {
roleService.doOtherThing();
}).start();
}
}

@Service
public class RoleService {

@Transactional
public void doOtherThing() {
System.out.println("保存role表数据");
}
}

存储引擎不支持事务

MyISAM不支持事务,InnoDB支持

错误的传播特性

1
2
3
4
5
6
7
8
9
@Service
public class UserService {

@Transactional(propagation = Propagation.NEVER)
public void add(UserModel userModel) {
saveData(userModel);
updateData(userModel);
}
}

异常处理不正确

开发者手动处理了异常,这样被代理的方法将无法捕获到异常,自然也就无法回滚。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Slf4j
@Service
public class UserService {

@Transactional
public void add(UserModel userModel) {
try {
saveData(userModel);
updateData(userModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}

另外,由于@Transactional默认捕获的异常是RuntimeExceptionError,如果抛出的是其他类型异常,则也会导致事务无法回滚。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Slf4j
@Service
public class UserService {

@Transactional
public void add(UserModel userModel) throws Exception {
try {
saveData(userModel);
updateData(userModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new Exception(e);
}
}
}
Other Articles
cover
回溯
  • 24/12/16
  • 15:20