前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java之Spring 框架实战: AOP

java之Spring 框架实战: AOP

原创
作者头像
IT工作者
发布2022-07-04 09:36:54
2950
发布2022-07-04 09:36:54
举报
文章被收录于专栏:程序技术知识

1 概述

Spring 的切面编程由 AspectJ 提供支持.

AOP 需要了解的基础:

使用 @Aspect 声明一个切面.

@After, @Before, @Around 定义 建言(advice); 这 3 个注解的参数 就是 切点(PointCut) , 所谓 切点 其实就是一个 拦截规则(可以由注解定义, 也可以由方法规则定义).

可以把 切点 用 @PonitCut 来定义, 然后放到 @After, @Before, @Around 当参数, 这样可以复用切点.

符合 拦截条件 的每一处 也是 连接点(JoinPoint).

2 AOP 示例

下面演示一下两种定义切点的方式:

基于自定义注解的切点 和 基于方法规则的切点.

本示例用到的代码已经放在 GitHub 上.

2.1 自定义一个切点注解 @MyAction

自定义一个注解 @MyAction 用来标记切点的位置:

代码语言:javascript
复制
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAction {
    String name();
}

注解本身没有功能, 就和 xml 一样.

注解和 xml 都是元数据(解释数据的数据), 也就是所谓的配置.

注解需要被其他程序解析才有用.

MyAction 在 切面定义 被解析成切点.

2.2 定义两个方法用来测试测点

定义两个方法, 在这两个方法上测试切点:

代码语言:javascript
复制
@Service
public class TestService {
    public void method1() {
        System.out.println("execute first method..");
    }

    @MyAction(name = "自定义注解")
    public void method2() {
        System.out.println("execute second method..");
    }
}

2.3 定义一个切面

代码语言:javascript
复制
@Aspect // 声明一个切面
@Component
public class TestAspect {
    // @Pointcut 用来定义切点. 这里把带有 @MyAction 注解的方法 视为切点.
    @Pointcut("@annotation(cn.mitrecx.learn2aop.aop.MyAction)")
    public void annotationPointCut() {
    }

    /**
     * After 注解用来声明一个建言, 这里使用 annotationPointCut() 定义的切点.
     * After 注解的方法 会在 切点执行之后 执行.
     * 换句话说, 在 切点方法 执行后, afterExecution 方法会紧接着被执行.
     */
    // @After("@annotation(cn.mitrecx.learn2aop.aop.MyAction)") // 和下面的 @After 等效
    @After("annotationPointCut()")
    public void afterExecution(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        MyAction action = method.getAnnotation(MyAction.class);
        System.out.println("After(注解式拦截): " + action.name());
    }

    /**
     * Before 注解用来声明一个建言, 这里使用 方法规则 定义的切点,
     * 方法规则 <code>execution(* cn.mitrecx.learn2aop.aop.TestService.*(..))</code> 表示 {@link TestService} 的所有方法.
     * <p>
     * 简而言之, 在 {@link TestService} 的任一方法开始执行前, 都先执行 beforeExecution 方法.
     */
    @Before("execution(* cn.mitrecx.learn2aop.aop.TestService.*(..))")
    public void beforeExecution(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        System.out.println("Before(方法规则式拦截): " + method.getName());
    }
}

上面 @Before 使用 方法规则式切点 不太好,它会导致 代码逻辑不清晰.

因为我们无法直接从 TestService 类里的方法 看出方法 “篡改” 了(被加了beforeExecution()逻辑).

2.4 配置类

代码语言:javascript
复制
@Configuration
@ComponentScan("cn.mitrecx.learn2aop.aop")
@EnableAspectJAutoProxy
public class AopConfig {
}

2.5 主程序

代码语言:javascript
复制
public class MyApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AopConfig.class);

        TestService testService = context.getBean(TestService.class);

        testService.method1();
        System.out.println("---------");
        testService.method2();

        context.close();
    }
}

运行结果:

Before(方法规则式拦截): method1

execute first method..

---------

Before(方法规则式拦截): method2

execute second method..

After(注解式拦截): 自定义注解

结果显示, 两个方法规则式切点(methed1, methed2) 的 @Before 建言 在切点方法执行前 被执行;

注解式切点(methed2) 的 @After 建言 在切点方法执行后 被执行.

注意:

这里只是为演示两种定义切点的方式.

个人建议只使用 注解式切点, 因为它看起来更清晰.

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 概述
  • 2 AOP 示例
    • 2.1 自定义一个切点注解 @MyAction
      • 2.2 定义两个方法用来测试测点
        • 2.3 定义一个切面
          • 2.4 配置类
            • 2.5 主程序
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档