作为 java web 开发者,ioc 和 aop 是两个核心概念需要掌握
基本概念解释
ioc 控制反转:
Inversion of Control,核心思想是:将对象的创建和依赖关系的管理交给 Spring 容器,而不是由开发者手动控制。传统方式 new UserService()
,现在 @Autowired
aop 面向切面编程:
Aspect-Oriented Programming,核心思想是:将横切关注点(如日志、事务管理、权限校验)与业务逻辑分离,通过切面(Aspect)统一管理这些逻辑
- 切面(Aspect):封装横切逻辑的类(如日志切面)
- 连接点(Join Point):程序执行的某个点(如方法调用)
- 切入点(Pointcut):定义在哪些连接点上应用切面逻辑
- 通知(Advice):切面逻辑的具体实现,有以下类型
- @Before:方法执行前。
- @After:方法执行后。
- @AfterReturning:方法成功返回后。
- @AfterThrowing:方法抛出异常后。
- @Around:环绕方法执行(可自定义逻辑)
IOC 经典使用场景
将对象的创建和依赖管理交给 Spring 容器
比如 springboot 中的使用这些注解
@Controller
@Service
@Mapper
@Autowire
// 自动发现并注册 Bean
@ComponentScan
// 定义 Bean
@Configuration
@Bean
AOP 经典使用场景
将横切逻辑(如日志、事务)与业务逻辑解耦
自定义一个注解
// 元注解:定义注解的行为
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留,可通过反射读取
@Target(ElementType.METHOD) // 注解只能用于方法上
public @interface LogExecution {
String value() default "Method executed"; // 成员变量(带默认值)
}
使用 aop 实现自定义注解的行为
@Aspect
@Component
public class LoggingAspect {
@Before("@annotation(logExecution)") // 匹配带有 @LogExecution 的方法
public void logBefore(JoinPoint joinPoint, LogExecution logExecution) {
System.out.println("【日志】方法: " + joinPoint.getSignature().getName());
System.out.println("描述: " + logExecution.value());
}
}
使用自定义注解
public class MyService {
@LogExecution("Processing data")
public void processData() {
System.out.println("Data processed");
}
}
aop 常常用在:
- 日志记录
- 参数验证
- 权限控制
- 性能监控等
其他
aop 中很多写逻辑时候,喜欢把 @Pointcut 切入点和 @Before/@Around 通知执行逻辑相分离,比如会这样写:
@Target(ElementType.METHOD) // 作用于方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时保留,支持反射读取
public @interface Loggable {
String value() default "Method executed"; // 可选参数
}
@Aspect
@Component
public class LoggingAspect {
// 定义切入点:匹配所有被 @Loggable 注解标记的方法
@Pointcut("@annotation(loggable)")
public void loggableMethods(Loggable loggable) {}
// 前置通知:在目标方法执行前插入逻辑
@Before("loggableMethods(loggable)")
public void beforeLoggableMethod(Loggable loggable) {
String logMessage = loggable.value();
System.out.println("【日志】" + logMessage + " - 方法执行前");
}
}
@Service
public class MyService {
@Loggable("Processing data")
public void processData() {
System.out.println("Data processed");
}
@Loggable
public void sayHello(String name) {
System.out.println("Hello, " + name);
}
loggableMethods 是一个 切点定义方法,它的方法体是空的,因为它只是一个标记,告诉 Spring AOP “在哪里拦截”,切点方法本身 不需要实现逻辑
其实使用上是建议使用 @Pointcut 的,因为如果多个通知(如 @Before、@After、@Around)需要 同一个切点,通过 @Pointcut 可以 复用切点表达式,避免重复代码。例如
@Pointcut("@annotation(loggable)")
public void loggableMethods(Loggable loggable) {}
@Before("loggableMethods(loggable)")
public void before(JoinPoint joinPoint, Loggable loggable) {
// 前置逻辑
}
@After("loggableMethods(loggable)")
public void after(JoinPoint joinPoint, Loggable loggable) {
// 后置逻辑
}