1. 什么是AOP?
AOP(Aspect-Oriented Programming,面向切面编程)是一种不同于传统面向对象编程(OOP)的编程方式。AOP的核心思想是通过将横跨多个业务逻辑的功能(如日志、事务、权限检查等)提取为切面(Aspect),从而使得核心业务逻辑更加简洁与专注。
AOP 与 OOP 的区别
-
OOP:将系统视为由多个对象进行交互和协作,每个对象拥有自己的状态和行为。
-
AOP:将系统分解为多个“切面”,即系统中的关注点,核心逻辑与切面逻辑分开处理。
举个例子:在一个 BookService 中,我们有多个业务方法,例如 createBook、updateBook 和 deleteBook。每个方法在执行前都需要进行安全检查、日志记录和事务处理。传统的OOP方式会将这些功能代码写在每个方法中,导致代码重复且不易维护。
AOP的出现帮助我们将这些横切关注点(如安全、日志、事务)抽离出来,避免重复代码,并且可以在不修改业务代码的情况下增强功能。
2. AOP 的基本术语
在AOP编程中,我们经常会遇到以下概念:
-
Aspect(切面):横跨多个核心逻辑的功能,系统中的一个关注点(例如,日志、事务、安全检查)。
-
Joinpoint(连接点):应用程序流程中可以插入切面代码的点。
-
Pointcut(切入点):一个连接点的集合,可以定义在哪些方法上执行切面代码。
-
Advice(增强):在连接点执行的具体动作,可以是前置增强、后置增强等。
-
Introduction(引介):为已有的Java对象动态增加新的接口。
-
Weaving(织入):将切面与目标对象的代码结合,在程序执行流程中动态应用切面。
-
Interceptor(拦截器):执行增强操作的具体方式。
-
Target Object(目标对象):核心业务逻辑的对象,通常是需要被增强的类。
-
AOP Proxy(AOP代理):客户端持有的、增强后的对象引用。
这些术语可能让你对AOP产生疑惑,但实际上,AOP本质上就是一种代理模式,在Spring容器中实现AOP非常简单。
3. AOP 的实现方式
AOP的目标是将切面逻辑与业务逻辑分离,Spring框架通过CGLIB和JDK动态代理来实现AOP。Spring支持通过注解和XML配置两种方式来实现AOP。我们将以Spring AOP为例,了解如何通过注解实现AOP。
4. Spring AOP 使用示例
假设我们有两个核心服务:UserService 和 MailService,并且需要为这些服务的业务方法添加日志功能。具体步骤如下:
4.1 引入Spring AOP依赖
首先,我们通过Maven引入Spring对AOP的支持:
xml<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.0</version></dependency>
4.2 定义切面类(LoggingAspect)
java@Aspect@Componentpublic class LoggingAspect {// 在执行UserService的每个方法前执行:@Before("execution(public * com.itranswarp.learnjava.service.UserService.*(..))")public void doAccessCheck() {System.err.println("[Before] do access check...");}// 在执行MailService的每个方法前后执行:@Around("execution(public * com.itranswarp.learnjava.service.MailService.*(..))")public Object doLogging(ProceedingJoinPoint pjp) throws Throwable {System.err.println("[Around] start " + pjp.getSignature());Object retVal = pjp.proceed();System.err.println("[Around] done " + pjp.getSignature());return retVal;}}
4.3 配置Spring AOP
在Spring配置类中,启用AOP支持:
java@Configuration@ComponentScan@EnableAspectJAutoProxypublic class AppConfig {// Spring配置}
4.4 执行结果
当我们运行应用程序时,AOP会在指定方法前后自动执行我们定义的增强操作。示例输出如下:
csharp[Before] do access check...[Around] start void com.itranswarp.learnjava.service.MailService.sendRegistrationMail(User)Welcome, test![Around] done void com.itranswarp.learnjava.service.MailService.sendRegistrationMail(User)[Before] do access check...[Around] start void com.itranswarp.learnjava.service.MailService.sendLoginMail(User)Hi, Bob! You are logged in at 2020-02-14T23:13:52.167996+08:00[Asia/Shanghai][Around] done void com.itranswarp.learnjava.service.MailService.sendLoginMail(User)
5. Spring AOP的代理模式
AOP的工作原理非常简单:Spring容器会自动为我们创建代理类。例如,LoggingAspect.doAccessCheck() 会被自动注入到 UserService 的每个方法执行之前。这一过程背后,Spring通过代理模式创建了一个增强后的 UserService 子类。具体过程如下:
javapublic class UserServiceAopProxy extends UserService {private UserService target;private LoggingAspect aspect;public UserServiceAopProxy(UserService target, LoggingAspect aspect) {this.target = target;this.aspect = aspect;}public User login(String email, String password) {aspect.doAccessCheck();return target.login(email, password);}public User register(String email, String password, String name) {aspect.doAccessCheck();return target.register(email, password, name);}}
通过这种方式,Spring容器自动为 UserService 创建了代理对象,并将切面方法(如 LoggingAspect)注入到代理对象中。
6. AOP的拦截器类型
在Spring AOP中,常见的拦截器类型如下:
-
@Before:在目标方法执行前执行。
-
@After:在目标方法执行后执行,无论目标方法是否抛出异常。
-
@AfterReturning:仅在目标方法正常返回时执行。
-
@AfterThrowing:仅在目标方法抛出异常时执行。
-
@Around:完全控制目标方法的执行,可以在执行前后、异常抛出后执行任意拦截代码。
7. 小结
Spring AOP提供了一种简洁的方式来增强应用程序的功能,特别适用于日志记录、权限检查和事务管理等横切关注点。通过使用注解和动态代理,Spring简化了AOP的实现,让开发者不必关心复杂的代理实现,专注于业务逻辑。
使用Spring AOP的步骤非常简单:
-
定义切面(Aspect),并用注解标明要在何处执行。
-
在切面类上使用
@Aspect和@Component注解。 -
在Spring配置类中启用
@EnableAspectJAutoProxy。
这样,我们就能轻松实现面向切面编程,从而使我们的业务代码更加清晰、简洁,且易于维护。
3627

被折叠的 条评论
为什么被折叠?



