IoC(控制反转)与AOP(面向切面编程)详解及示例
1. IoC(控制反转)
核心思想:将对象的创建和依赖管理交给容器,而非在代码中硬编码依赖关系,实现解耦。
依赖注入(DI)是IoC的一种实现方式,常见形式包括:构造器注入、Setter注入、字段注入。
示例:传统代码 vs. Spring IoC
传统代码(紧耦合):
java
public class UserService {
// 直接创建依赖对象(紧耦合)
private UserDao userDao = new UserDaoImpl();
public void saveUser(User user) {
userDao.save(user);
}
}
使用Spring IoC(解耦):
- 定义接口和实现类:
java
public interface UserDao {
void save(User user);
}
@Component // 声明为Spring管理的Bean
public class UserDaoImpl implements UserDao {
public void save(User user) {
System.out.println("保存用户: " + user);
}
}
@Service // 声明Service层Bean
public class UserService {
@Autowired // 自动注入依赖
private UserDao userDao;
public void saveUser(User user) {
userDao.save(user);
}
}
- 配置Spring容器(Java Config):
java
@Configuration
@ComponentScan("com.example") // 扫描包下的组件
public class AppConfig {
}
- 使用容器获取Bean:
java
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.saveUser(new User("Alice"));
}
}
关键点:
@Component
、@Service
等注解将类交给Spring管理。@Autowired
自动注入依赖,无需手动创建对象。- 容器 (
ApplicationContext
) 负责Bean的生命周期和依赖关系。
2. AOP(面向切面编程)
核心思想:将横切关注点(如日志、事务)从业务逻辑中分离,通过切面(Aspect)统一处理,提升模块化。
AOP核心概念:
- 切面(Aspect):封装横切逻辑的模块(如日志切面)。
- 连接点(Join Point):程序执行的点(如方法调用)。
- 通知(Advice):在连接点执行的动作(如
@Before
、@After
)。 - 切点(Pointcut):匹配连接点的表达式(如
execution(* com.example.service.*.*(..))
)。
示例:日志切面
- 定义切面类:
java
@Aspect // 声明为切面
@Component // 由Spring管理
public class LoggingAspect {
// 定义切点:匹配service包下所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 前置通知:方法执行前记录日志
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("方法调用前: " + methodName);
}
// 后置通知:方法执行后记录日志(无论是否异常)
@After("serviceMethods()")
public void logAfter(JoinPoint joinPoint) {
System.out.println("方法调用后: " + joinPoint.getSignature().getName());
}
// 环绕通知:统计方法执行时间
@Around("serviceMethods()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行目标方法
long duration = System.currentTimeMillis() - start;
System.out.println("方法执行耗时: " + duration + "ms");
return result;
}
}
- 启用AOP支持:
java
@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy // 启用AOP自动代理
public class AppConfig {
}
- 业务类:
java
@Service
public class OrderService {
public void createOrder() {
System.out.println("创建订单...");
}
}
- 测试AOP效果:
java
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = context.getBean(OrderService.class);
orderService.createOrder();
}
}
输出结果:
方法调用前: createOrder
创建订单...
方法调用后: createOrder
方法执行耗时: 2ms
总结
-
IoC优势:
- 降低耦合度,提升代码可维护性。
- 便于单元测试(依赖可Mock注入)。
-
AOP优势:
- 横切关注点集中管理,避免代码重复。
- 提升系统可扩展性(如动态添加日志、事务)。
应用场景:
- IoC广泛用于管理Bean依赖(如Service依赖DAO)。
- AOP适用于日志、事务、权限校验、性能监控等场景。