本文,我们来谈谈面向切面编程。
什么是面向切面编程
面向切面编程(Aspect Oriented Program, 简称 AOP
)是一种编程范式,用于解藕系统中的横切关注点。
这很抽象。
我们换种理解~
面向切面编程把业务功能分为核心、非核心两部分。比如:
- 核心业务功能:用户登陆、增加数据、删除数据
- 非核心业务功能:性能统计、日志、事务管理
在 Spring
的面向编程思想中,非核心业务功能被定义为切面。核心业务功能和切面功能(非核心功能)被分别进行独立开发,然后把切面功能和核心业务功能编织在一起,这就是 AOP
。
AOP 中的概念
术语 | 解析 |
---|---|
切入点 pointcut |
在哪些类、哪些方法上切入 |
通知 advice |
在方法前、方法后、方法前后做了什么 |
切面 aspect |
切面 = 切入点 + 通知 |
织入 weaving |
把切面加入对象,并创建出代理对象的过程 |
环绕通知 | AOP 中最强大、灵活的通知,它集成了前置和后置通知,保留了连接点原有的方法 |
案例图解
未使用 AOP
使用 AOP
简单案例
假设我们开发一个简单用户管理系统。
添加 aspect
依赖:
org.aspectj
aspectjweaver
1.9.19
我们创建一个切面类,定义了我们要应用的横切关注点。
package com.launch;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.launch.UserService.addUser(..))")
public void logBeforeAddUser() {
System.out.println("Before adding a user...");
}
@Before("execution(* com.launch.UserService.deleteUser(..))")
public void logBeforeDeleteUser() {
System.out.println("Before deleting a user...");
}
}
我们创建了名为 LoggingAspect
的切面类,并使用 @Before
注释定义了两个通知方法。这两个通知分别在执行 com.example.UserService.addUser()
和 com.example.UserService.deleteUser()
方法之前打印日志。
接下来,我们创建名为 UserService
类,并添加 @Service
注解:
package com.launch;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void addUser(String username) {
// add logic
System.out.println("add logic " + username);
}
public void deleteUser(String username) {
// remove logic
System.out.println("delete logic " + username);
}
}
然后我们在程序入口文件中添加 @EnableAspectJAutoProxy
注解,以启用 AOP
:
package com.launch;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy
public class LaunchApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(LaunchApplication.class);
app.run(args);
}
}
然后我们创建名为 JimmyController
的类进行测试:
package com.launch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class JimmyController {
@Autowired
private UserService userService;
@RequestMapping("/add_and_delete")
public String addUser() {
userService.addUser("Jimmy");
userService.deleteUser("Jimmy");
return "Add Jimmy.";
}
}
这里我们触发 Get
请求 http://localhost:8080/add_and_delete
接口就可以看到下面的结果:
参考
- 《Spring Boot 实战派》