AOP与IOC详解
一、IOC (控制反转)
1. 基本概念
IOC (Inversion of Control,控制反转) 是一种设计原则,用于降低代码之间的耦合度。它将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。
2. 核心思想
- 控制反转:将对象的创建、依赖关系的管理从应用程序代码中反转给外部容器
- 依赖注入(DI):IOC的一种实现方式,通过构造函数、setter方法或接口注入依赖对象
3. 实现方式
(1) 依赖注入的三种形式
// 1. 构造函数注入
public class UserService {
private UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
// 2. Setter方法注入
public class UserService {
private UserRepository userRepository;
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
// 3. 接口注入
public interface RepositoryAware {
void setRepository(UserRepository userRepository);
}
public class UserService implements RepositoryAware {
private UserRepository userRepository;
@Override
public void setRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
(2) Spring中的IOC容器
- BeanFactory:基础容器,提供基本的DI支持
- ApplicationContext:扩展了BeanFactory,提供更多企业级功能
- ClassPathXmlApplicationContext
- FileSystemXmlApplicationContext
- AnnotationConfigApplicationContext
4. 优势
- 降低组件之间的耦合度
- 提高代码的可测试性
- 使应用程序更易于配置和管理
- 促进面向接口编程
二、AOP (面向切面编程)
1. 基本概念
AOP (Aspect-Oriented Programming,面向切面编程) 是一种编程范式,旨在将横切关注点(如日志、事务、安全等)与业务逻辑分离,提高模块化程度。
2. 核心概念
- 切面(Aspect):横切关注点的模块化
- 连接点(Joinpoint):程序执行过程中的某个特定点
- 通知(Advice):在特定连接点执行的动作
- 切入点(Pointcut):匹配连接点的表达式
- 引入(Introduction):为类添加新方法或属性
- 目标对象(Target Object):被一个或多个切面通知的对象
- AOP代理(AOP Proxy):由AOP框架创建的对象,用于实现切面契约
- 织入(Weaving):将切面与其他应用类型或对象连接的过程
3. 通知类型
// 1. 前置通知(Before advice)
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
// 在方法执行前执行
}
// 2. 后置通知(After returning advice)
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
// 在方法正常返回后执行
}
// 3. 异常通知(After throwing advice)
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
// 在方法抛出异常后执行
}
// 4. 最终通知(After (finally) advice)
@After("execution(* com.example.service.*.*(..))")
public void afterAdvice(JoinPoint joinPoint) {
// 在方法执行后执行(无论是否抛出异常)
}
// 5. 环绕通知(Around advice)
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
// 在方法调用前后执行自定义行为
Object result = joinPoint.proceed();
return result;
}
4. AOP实现方式
(1) 动态代理
- JDK动态代理:基于接口
- CGLIB代理:基于类继承
(2) Spring AOP与AspectJ
-
Spring AOP:
- 基于代理实现
- 仅支持方法级别的连接点
- 运行时织入
- 与Spring IOC容器集成
-
AspectJ:
- 完整的AOP实现
- 支持字段、构造器、方法等更多连接点
- 编译时或加载时织入
- 功能更强大但配置更复杂
5. 典型应用场景
- 日志记录
- 事务管理
- 安全控制
- 性能监控
- 异常处理
- 缓存
三、IOC与AOP的关系
- 协同工作:在Spring框架中,AOP的实现依赖于IOC容器管理的Bean
- 分工不同:
- IOC解决对象创建和依赖关系问题
- AOP解决横切关注点问题
- 实现机制:
- AOP代理对象通常由IOC容器创建和管理
- AOP增强了IOC管理的Bean的功能
四、Spring中的配置示例
1. 基于XML的配置
<!-- IOC配置 -->
<bean id="userRepository" class="com.example.UserRepositoryImpl"/>
<bean id="userService" class="com.example.UserService">
<property name="userRepository" ref="userRepository"/>
</bean>
<!-- AOP配置 -->
<aop:config>
<aop:aspect id="logAspect" ref="loggingAspect">
<aop:pointcut id="serviceMethods" expression="execution(* com.example.service.*.*(..))"/>
<aop:before pointcut-ref="serviceMethods" method="logBefore"/>
</aop:aspect>
</aop:config>
<bean id="loggingAspect" class="com.example.LoggingAspect"/>
2. 基于注解的配置
// IOC配置
@Configuration
@ComponentScan("com.example")
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepositoryImpl();
}
}
// AOP配置
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
// 前置通知逻辑
}
}
五、总结
特性 | IOC | AOP |
---|---|---|
目的 | 管理对象创建和依赖关系 | 分离横切关注点 |
核心概念 | 容器、Bean、依赖注入 | 切面、连接点、通知、切入点 |
实现方式 | 工厂模式、反射 | 动态代理、字节码增强 |
应用场景 | 解耦、可测试性 | 日志、事务、安全等横切关注点 |
Spring实现 | BeanFactory/ApplicationContext | Spring AOP/AspectJ集成 |
IOC和AOP是Spring框架的两大核心,它们共同为构建松耦合、可维护的企业级应用提供了坚实的基础。理解这两者的原理和实现方式,对于掌握Spring框架至关重要。