AOP 编程
AOP 编程
专业名词介绍:
- Aspect:切面,即一个横跨多个核心逻辑的功能,或者称之为系统关注点;
- Joinpoint:连接点,即定义在应用程序流程的何处插入切面的执行;
- Pointcut:切入点,即一组连接点的集合;
- Advice:增强,指特定连接点上执行的动作;
- Introduction:引介,指为一个已有的Java对象动态地增加新的接口;
- Weaving:织入,指将切面整合到程序的执行流程中;
- Interceptor:拦截器,是一种实现增强的方式;
- Target Object:目标对象,即真正执行业务的核心逻辑对象;
- AOP Proxy:AOP代理,是客户端持有的增强后的对象引用。
1. 定义切面
- 引入相关支持
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 开启注解支持
配置类或启动类添加 @EnableAspectJAutoProxy
- 定义切面并添加增强方法
@Aspect
@Component
public class LogingAspect {
// 在执行PersonService的每个方法前执行:
@Before("execution(public * com.zbm.test.controller.PersonService.*(..))")
public void doAccessCheck() {
System.err.println("[Before] do access check...");
}
// 在执行PersonService的每个方法前后执行:
@Around("execution(public * com.zbm.test.controller.PersonService.*(..))")
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;
}
}
以上就是 Spring 实现 AOP 编程的注解方法,这是其中最为简单的一种方法,其底层主要是 JDK 动态代理或者 CGLIB 动态代理来实现,使用哪一种取决于委托类是否可继承。
- 其他增强类型
- @Before:这种拦截器先执行拦截代码,再执行目标代码。如果拦截器抛异常,那么目标代码就不执行了;
- @After:这种拦截器先执行目标代码,再执行拦截器代码。无论目标代码是否抛异常,拦截器代码都会执行;
- @AfterReturning:和@After不同的是,只有当目标代码正常返回时,才执行拦截器代码;
- @AfterThrowing:和@After不同的是,只有当目标代码抛出了异常时,才执行拦截器代码;
- @Around:能完全控制目标代码是否执行,并可以在执行前后、抛异常后执行任意拦截代码,可以说是包含了上面所有功能。
2. 使用注解装配 AOP
- 定义注解
/**
* 监控时间
*
* @author Andrew
* @date 2022/6/22
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MetricTime {
String value();
}
- 定义切面
/**
* 监控时间切面
*
* @author Andrew
* @date 2022/6/22
*/
@Aspect
@Component
public class MetricAspect {
/**
* 环绕通知
*
* @param joinPoint 连接点
* @param metricTime 注解
* @return Object
* @throws Throwable 异常
*/
@Around("@annotation(metricTime)")
public Object metric(ProceedingJoinPoint joinPoint, MetricTime metricTime) throws Throwable {
String name = metricTime.value();
long start = System.currentTimeMillis();
try {
return joinPoint.proceed();
} finally {
long t = System.currentTimeMillis() - start;
// 写入日志或发送至JMX:
System.err.println("[Metrics] " + name + ": " + t + "ms");
}
}
}
- 使用注解
/**
* @author Andrew
* @date 2022/6/16
*/
@Component
public class PersonService {
@MetricTime("register")
public void outputPersonInfo(Person person) {
if (person != null) {
System.out.println(person.toString());
}
}
}
类似于 @Translation 开启事务注解一样,在方法上加了此注解将会开启方法增强,比上一种通过表达式来模糊匹配更为精准一些。
3. 使用注意事项
- 访问被注入的Bean时,总是调用方法而非直接访问字段;
- 编写Bean时,如果可能会被代理,就不要编写
public final
方法。
引用:
https://www.liaoxuefeng.com/wiki/1252599548343744/1266265125480448
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
2021-07-01 Kafka Range RoundRobin 和Sticky 三种 分区分配策略