springboot重点
springboot重点
下面简单介绍一下 Spring Boot 框架中两个至关重要的设计理念:IOC(控制反转)和 AOP(面向切面编程)。
控制反转(IOC)
- 定义: 控制反转是一种设计模式,其核心思想是将对象的创建与管理交由 Spring 容器处理,而非在代码中硬编码实例化。也就是说,应用程序不再主动创建依赖对象,而是通过依赖注入(DI)的方式,由容器在运行时将所需组件动态注入到目标对象中。
- 优点:
- 解耦合: 各个组件间不再直接依赖具体实现,使得模块之间的耦合度大幅降低。
- 便于测试: 由于依赖关系通过注入管理,替换为 Mock 对象或其他实现就变得简单。
- 灵活性和可维护性: 组件的生命周期与配置完全交由 Spring 管理,开发者只需专注于业务逻辑,实现“关注点分离”。
就像拥有一位超级管家,自动处理组件之间的依赖关系,让开发者能够专注于“创意设计”而非“后勤保障”。
面向切面编程(AOP)
- 定义: AOP 是一种编程范式,==用于将那些横切关注点(例如日志记录、事务管理、安全控制等)与核心业务逻辑分离==。通过在代码运行的不同阶段(方法调用前、后或异常时)动态地插入特定的“切面”,AOP 实现了业务逻辑与通用功能的解耦。
- 工作原理:
- 切面(Aspect): 定义了横切关注点的逻辑,包含通知(Advice)和切点(Pointcut)。
- 通知(Advice): 指定在特定时刻执行的操作,比如方法执行前后。
- 切点(Pointcut): 定位到需要增强的目标方法。
- 代理模式: Spring 通常通过代理技术,在调用目标方法时先执行切面中的额外逻辑,再调用目标方法,从而实现“无侵入”式的功能扩展。
- 优点:
- 代码复用: 横切关注点集中管理,避免在每个业务方法中重复编写相同的代码。
- 提高可维护性: 修改公共逻辑时只需调整一个切面即可,无需触及核心业务代码。
- 业务逻辑纯粹: 让代码更易读、更专注于实现核心业务,增强整体架构的清晰度。
想象一下,AOP 就像给每个方法装上了“智能护盾”,在不干扰核心功能的同时,自动处理那些重复又关键的横向任务。
小结
- IOC 使得组件之间的依赖关系由 Spring 容器管理,解除了组件之间的硬编码依赖,极大地提升了代码的灵活性和测试性。
- AOP 则将横切关注点(如日志、事务、安全等)抽离出来,以切面的形式统一管理,让业务逻辑更加专注和清晰。
1. IOC 示例
在 IOC(控制反转)中,组件之间的依赖关系由 Spring 容器管理。举个例子,我们可以定义一个业务逻辑类(Service),然后在 Controller 中通过依赖注入(DI)的方式使用它。如下代码展示了如何用注解实现这一过程:
▼java复制代码// UserService.java package com.example.demo.service; import org.springframework.stereotype.Service; @Service // 将该类注册为 Spring Bean public class UserService { public String getUserInfo() { return "这是用户信息。"; } }
▼java复制代码// UserController.java package com.example.demo.controller; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController // 定义为 REST 风格的控制器 public class UserController { @Autowired // 依赖注入,将 UserService 注入到 UserController 中 private UserService userService; @GetMapping("/user") public String getUser() { // 通过容器管理的 UserService 获取用户信息 return userService.getUserInfo(); } }
说明:
- @Service 注解告诉 Spring,该类是一个业务层组件,容器将自动创建其实例。
- @Autowired 注解用于自动注入依赖,使得 UserController 不需要自己实例化 UserService,从而实现了 IOC。
- 整个过程使得组件之间的耦合度降低,方便后续扩展和单元测试。
2. AOP 示例
AOP(面向切面编程)用于将横切关注点(如日志、事务、安全等)从业务逻辑中分离出来。下面的示例展示了如何利用 AOP 实现方法调用前的日志记录。
▼java复制代码// LoggingAspect.java package com.example.demo.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect // 声明一个切面 @Component // 让 Spring 管理这个切面组件 public class LoggingAspect { // 定义切点:拦截 com.example.demo.service 包下所有方法的执行 @Before("execution(* com.example.demo.service.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("【日志】调用方法:" + joinPoint.getSignature().getName()); } }
说明:
- @Aspect 注解表明该类是一个切面,包含了横切逻辑。
- @Before 注解定义了一个前置通知,即在目标方法执行前会执行
logBefore方法。 - 切点表达式
"execution(* com.example.demo.service.*.*(..))"表示拦截com.example.demo.service包中所有类的任意方法。 - 通过这种方式,我们不需要在每个业务方法中手动添加日志记录代码,而是由 AOP 自动处理,从而保持业务代码的简洁与专注。
总结
- IOC 示例: 通过注解
@Service和@Autowired,Spring 自动管理组件的实例化和依赖注入,解耦了组件之间的关系。 - AOP 示例: 通过定义切面和通知(如
@Before),Spring AOP 在方法调用前统一处理横切关注点(例如日志记录),使业务逻辑更纯粹。
1. 业务接口与多实现(IOC 实践)
首先定义一个支付服务接口,并提供两种实现——分别模拟信用卡和 PayPal 的支付处理。利用 @Service 注解,Spring 容器将自动将它们纳入管理。
▼java复制代码// PaymentService.java package com.example.demo.service; public interface PaymentService { String processPayment(double amount); }
▼java复制代码// CreditCardPaymentService.java package com.example.demo.service; import org.springframework.stereotype.Service; @Service("creditCardPaymentService") public class CreditCardPaymentService implements PaymentService { @Override public String processPayment(double amount) { // 模拟信用卡支付的处理过程 try { Thread.sleep(200); // 模拟延时 } catch (InterruptedException e) { e.printStackTrace(); } return "信用卡支付 $" + amount + " 成功处理。"; } }
▼java复制代码// PaypalPaymentService.java package com.example.demo.service; import org.springframework.stereotype.Service; @Service("paypalPaymentService") public class PaypalPaymentService implements PaymentService { @Override public String processPayment(double amount) { // 模拟 PayPal 支付的处理过程 try { Thread.sleep(300); // 模拟延时 } catch (InterruptedException e) { e.printStackTrace(); } return "PayPal 支付 $" + amount + " 成功处理。"; } }
在上述代码中,通过 @Service("...") 为每个实现指定了标识符,方便后续在依赖注入时精准选择所需实现。
2. 核心业务处理类与依赖注入
接下来定义一个业务处理类 PaymentProcessor,它通过构造器注入方式使用了 PaymentService 接口。这里我们利用 @Qualifier 指定使用信用卡支付服务(您可灵活切换到其他实现而不改动核心逻辑)。
▼java复制代码// PaymentProcessor.java package com.example.demo.processor; import com.example.demo.service.PaymentService; import com.example.demo.annotation.TrackTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @Component public class PaymentProcessor { private PaymentService paymentService; // 通过 @Qualifier 指定具体的实现,这就是 IOC 的魅力:解耦依赖! @Autowired public PaymentProcessor(@Qualifier("creditCardPaymentService") PaymentService paymentService) { this.paymentService = paymentService; } // 业务方法上标记自定义注解,用于 AOP 切面监控执行时间 @TrackTime public void process(double amount) { String result = paymentService.processPayment(amount); System.out.println(result); } }
通过这种设计,即便将来支付方式发生变化,只需调整依赖注入的配置或切换 @Qualifier 参数,业务逻辑代码完全无需修改。
3. 自定义注解与 AOP 环绕通知
为了监控方法执行时间,我们定义一个自定义注解 @TrackTime,并编写 AOP 切面 LoggingAspect。切面中采用了 @Around 环绕通知,在方法执行前后计算耗时,并记录相关日志。
▼java复制代码// TrackTime.java package com.example.demo.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface TrackTime { }
▼java复制代码// LoggingAspect.java package com.example.demo.aspect; import com.example.demo.annotation.TrackTime; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { @Around("@annotation(trackTime)") public Object logExecutionTime(ProceedingJoinPoint joinPoint, TrackTime trackTime) throws Throwable { long start = System.currentTimeMillis(); System.out.println("【AOP日志】方法 " + joinPoint.getSignature().getName() + " 开始执行..."); Object proceed = joinPoint.proceed(); // 执行目标方法 long executionTime = System.currentTimeMillis() - start; System.out.println("【AOP日志】方法 " + joinPoint.getSignature().getName() + " 执行完毕,耗时 " + executionTime + " 毫秒"); return proceed; } }
这种设计不仅帮助企业监控关键业务方法的性能,还能方便地在需要时添加更多横切逻辑(如权限验证、异常监控等),保持核心代码的整洁。
4. 控制器入口
最后,我们通过一个 REST 接口来触发支付流程,测试整个系统的协作效果。
▼java复制代码// PaymentController.java package com.example.demo.controller; import com.example.demo.processor.PaymentProcessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class PaymentController { @Autowired private PaymentProcessor paymentProcessor; @GetMapping("/pay") public String makePayment(@RequestParam("amount") double amount) { paymentProcessor.process(amount); return "支付流程已触发!"; } }
访问 /pay?amount=100 后,您将看到支付信息输出,并在控制台打印出 AOP 切面的执行日志。
