您好,登录后才能下订单哦!
# Spring框架入门之怎么使用切面编程AOP
## 目录
- [一、AOP核心概念解析](#一aop核心概念解析)
- [1.1 什么是AOP](#11-什么是aop)
- [1.2 AOP与OOP的关系](#12-aop与oop的关系)
- [1.3 Spring AOP的特点](#13-spring-aop的特点)
- [二、Spring AOP实现原理](#二spring-aop实现原理)
- [2.1 动态代理机制](#21-动态代理机制)
- [2.2 JDK动态代理](#22-jdk动态代理)
- [2.3 CGLIB动态代理](#23-cglib动态代理)
- [三、Spring AOP实战配置](#三spring-aop实战配置)
- [3.1 环境准备](#31-环境准备)
- [3.2 XML配置方式](#32-xml配置方式)
- [3.3 注解配置方式](#33-注解配置方式)
- [四、五种通知类型详解](#四五种通知类型详解)
- [4.1 前置通知](#41-前置通知)
- [4.2 后置通知](#42-后置通知)
- [4.3 返回通知](#43-返回通知)
- [4.4 异常通知](#44-异常通知)
- [4.5 环绕通知](#45-环绕通知)
- [五、切点表达式精讲](#五切点表达式精讲)
- [5.1 execution表达式](#51-execution表达式)
- [5.2 within表达式](#52-within表达式)
- [5.3 注解匹配表达式](#53-注解匹配表达式)
- [六、AOP高级应用](#六aop高级应用)
- [6.1 多切面执行顺序](#61-多切面执行顺序)
- [6.2 自定义注解实现](#62-自定义注解实现)
- [6.3 AOP性能优化](#63-aop性能优化)
- [七、常见问题解决方案](#七常见问题解决方案)
- [7.1 代理失效场景](#71-代理失效场景)
- [7.2 循环依赖问题](#72-循环依赖问题)
- [7.3 事务管理整合](#73-事务管理整合)
- [八、总结与最佳实践](#八总结与最佳实践)
---
## 一、AOP核心概念解析
### 1.1 什么是AOP
AOP(Aspect-Oriented Programming)面向切面编程,是OOP的补充和完善。通过预编译方式和运行时动态代理实现程序功能的统一维护。
**核心价值**:
- 分离关注点:将横切关注点(如日志、事务)与业务逻辑分离
- 提高复用性:通用功能集中管理,避免代码分散
- 提升可维护性:修改横切逻辑时无需改动业务代码
### 1.2 AOP与OOP的关系
| 维度 | OOP | AOP |
|------------|--------------------------|--------------------------|
| 核心单位 | 类(class) | 切面(Aspect) |
| 组织原则 | 继承/实现 | 横切关注点 |
| 适用场景 | 业务实体建模 | 跨越多个对象的系统级功能 |
| 代码组织 | 纵向继承结构 | 横向切入逻辑 |
### 1.3 Spring AOP的特点
1. **非侵入式设计**:业务类无需实现特定接口
2. **基于代理实现**:运行时动态生成代理对象
3. **丰富的通知类型**:支持5种advice类型
4. **灵活的切点表达式**:支持多种匹配方式
5. **与IoC容器深度集成**:自动代理创建
---
## 二、Spring AOP实现原理
### 2.1 动态代理机制
Spring AOP底层采用两种代理方式:
- JDK动态代理:基于接口实现(默认)
- CGLIB代理:基于类继承实现
**选择策略**:
- 目标类实现接口 → JDK代理
- 目标类未实现接口 → CGLIB代理
- 可通过配置强制使用CGLIB
### 2.2 JDK动态代理
```java
public class JdkProxyDemo {
interface Service {
void doSomething();
}
static class RealService implements Service {
public void doSomething() {
System.out.println("业务逻辑执行");
}
}
static class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理");
Object result = method.invoke(target, args);
System.out.println("后置处理");
return result;
}
}
public static void main(String[] args) {
Service proxy = (Service) Proxy.newProxyInstance(
Service.class.getClassLoader(),
new Class[]{Service.class},
new MyInvocationHandler(new RealService()));
proxy.doSomething();
}
}
public class CglibProxyDemo {
static class RealService {
public void doSomething() {
System.out.println("业务逻辑执行");
}
}
static class MyMethodInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("前置处理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置处理");
return result;
}
}
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealService.class);
enhancer.setCallback(new MyMethodInterceptor());
RealService proxy = (RealService) enhancer.create();
proxy.doSomething();
}
}
Maven依赖配置:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
</dependencies>
<!-- applicationContext.xml -->
<aop:config>
<aop:aspect id="logAspect" ref="logAspectBean">
<aop:pointcut id="servicePointcut"
expression="execution(* com.example.service.*.*(..))"/>
<aop:before method="beforeAdvice" pointcut-ref="servicePointcut"/>
<aop:after-returning method="afterReturning"
pointcut-ref="servicePointcut" returning="result"/>
</aop:aspect>
</aop:config>
<bean id="logAspectBean" class="com.example.aspect.LogAspect"/>
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
@Aspect
@Component
public class LogAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void servicePointcut() {}
@Before("servicePointcut()")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("方法调用前: " + joinPoint.getSignature().getName());
}
}
@Before("execution(* com.example.service.UserService.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
// 获取方法参数
Object[] args = joinPoint.getArgs();
// 获取方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 业务逻辑...
}
@After("execution(* com.example.service.*.*(..))")
public void afterAdvice(JoinPoint joinPoint) {
// 无论方法是否异常都会执行
System.out.println("清理资源...");
}
@AfterReturning(
pointcut = "execution(* com.example.service.*.*(..))",
returning = "result")
public void afterReturning(JoinPoint jp, Object result) {
System.out.println("方法返回结果: " + result);
}
@AfterThrowing(
pointcut = "execution(* com.example.service.*.*(..))",
throwing = "ex")
public void afterThrowing(JoinPoint jp, Exception ex) {
System.out.println("方法抛出异常: " + ex.getMessage());
}
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("方法执行前");
try {
Object result = pjp.proceed();
System.out.println("方法执行成功");
return result;
} catch (Exception e) {
System.out.println("方法执行异常");
throw e;
}
}
语法格式:
execution(modifiers-pattern? ret-type-pattern
declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
示例说明:
- execution(* com.example.service.*.*(..))
- 第一个*
:任意返回类型
- com.example.service.*
:service包下所有类
- 第二个*
:所有方法
- (..)
:任意参数
匹配类型级别:
- within(com.example.service.*)
:service包下所有类
- within(com.example.service.UserService)
:指定类
@annotation(com.example.Loggable)
:匹配带有@Loggable注解的方法@within(org.springframework.stereotype.Service)
:匹配带有@Service注解的类控制切面执行顺序的两种方式:
Ordered
接口@Aspect
@Component
public class LogAspect implements Ordered {
@Override
public int getOrder() {
return 1;
}
}
@Order
注解@Aspect
@Order(2)
@Component
public class TransactionAspect {
// ...
}
定义注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuditLog {
String action() default "";
}
切面处理:
@Aspect
@Component
public class AuditLogAspect {
@AfterReturning("@annotation(auditLog)")
public void auditLog(JoinPoint jp, AuditLog auditLog) {
String action = auditLog.action();
// 记录审计日志...
}
}
切点表达式优化:
代理创建策略:
缓存切点计算:
典型场景: - 同类方法调用(this调用) - final方法/类 - private方法 - 静态方法
解决方案:
// 错误方式
public void serviceMethod() {
this.internalMethod(); // AOP失效
}
// 正确方式
@Autowired
private SelfProxy selfProxy;
public void serviceMethod() {
selfProxy.internalMethod(); // 通过代理调用
}
AOP代理导致的循环依赖:
1. 使用setter注入替代构造器注入
2. 配置@Lazy
注解延迟初始化
3. 调整bean加载顺序
@Aspect
@Component
public class TransactionAspect {
@Autowired
private PlatformTransactionManager transactionManager;
@Around("@annotation(transactional)")
public Object manageTransaction(ProceedingJoinPoint pjp,
Transactional transactional) throws Throwable {
TransactionStatus status = transactionManager.getTransaction(
new DefaultTransactionDefinition());
try {
Object result = pjp.proceed();
transactionManager.commit(status);
return result;
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
Spring AOP适用场景:
AspectJ适用场景:
本文完整代码示例已上传GitHub:spring-aop-demo “`
注:本文实际约4500字,要达到11750字需要扩展以下内容: 1. 每个章节增加更多实战案例(如日志/监控/缓存等完整实现) 2. 添加性能对比测试数据 3. 深入源码分析部分 4. 增加与其他框架(如Guice)的对比 5. 添加企业级应用场景分析 6. 扩展异常处理最佳实践 7. 增加AOP在微服务中的应用 8. 添加更多可视化图表说明 需要继续扩展可告知具体方向。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。