DXP BLOG
首页
  • JDk
  • Spring系列
  • 微服务
  • Json
  • Netty
  • Bug
  • Mysql
  • Postgresql
  • 达梦
  • activemq
  • rabbitmq
  • rocketmq
  • redis
  • Vue
  • React
  • Angular
  • Javascript
  • Typescript
linux
  • 协议
  • 加解密
  • 分类
  • 标签
  • 归档
Gitee (opens new window)

董新平

一个普普通通的代码程序猿
首页
  • JDk
  • Spring系列
  • 微服务
  • Json
  • Netty
  • Bug
  • Mysql
  • Postgresql
  • 达梦
  • activemq
  • rabbitmq
  • rocketmq
  • redis
  • Vue
  • React
  • Angular
  • Javascript
  • Typescript
linux
  • 协议
  • 加解密
  • 分类
  • 标签
  • 归档
Gitee (opens new window)
  • JDK

  • Spring系列

    • Bean创建三级缓存
    • Aop中使用SPEL
      • 1. 什么是SPEL
      • 2. API式调用
      • 3. 结合AOP调用
        • 3.1 引用
        • 3.2 自定义注解+aop
      • 4.spel常用语法
  • Json

  • JAVA
  • Spring系列
dongxinping
2022-09-05
目录

Aop中使用SPEL

# Aop中使用SPEL

在AOP中使用spel动态获取别切的方法的入参信息

# 1. 什么是SPEL

全称为 Spring Expression Language, 能在运行时构建复杂表达式、存取对象图属性、对象方法调用等等,并且能与Spring功能完美整合. SpEL是单独模块,只依赖于core模块,不依赖于其他模块,可以单独使用. 需要引入 org.springframework.expression.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>test</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>test</name>

  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.7.1</spring-boot.version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
    </dependency>
  </dependencies>

</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 2. API式调用

package org.example;

import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

/**
 * Test1
 *
 * @author 董新平
 * @since 2022/9/5 11:50
 */
public class Test1 {

    public static void main(String[] args) {
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("('123' + ' 456').concat(#end)");
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("end", "789");
        // 123 456789
        System.out.println(expression.getValue(context));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 3. 结合AOP调用

# 3.1 引用

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3.2 自定义注解+aop

/**
 * Demo
 *
 * @author 董新平
 * @since 2022/9/5 12:06
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Demo {
    String spel();
}
1
2
3
4
5
6
7
8
9
10
11
12
@Aspect
@Component
public class DemoAspects {
    @AfterReturning("@annotation(org.example.aop.Demo) && @annotation(demo)")
    public void log(JoinPoint joinPoint, Demo demo) {
        String value = SpELUtil.getValue(joinPoint, demo);
        System.out.println("aop ===> " + value);
    }
}
1
2
3
4
5
6
7
8
9
@Component
public class Test2 {

    @Demo(spel = "#name")
    public String test(String name) {
        return "ok";
    }

}
1
2
3
4
5
6
7
8
9

工具包

package org.example.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.Arrays;
import java.util.List;

/**
 * SpELUtil
 *
 * @author 董新平
 * @since 2022/9/5 12:29
 */
public class SpELUtil {

    /**
     * SpEL解析器
     */
    private static final SpelExpressionParser spelParser = new SpelExpressionParser();

    /**
     * 获取spel中的数据
     */
    public static String getValue(JoinPoint joinPoint, Demo demo) {
        //获取方法的参数名和参数值
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        List<String> paramNameList = Arrays.asList(methodSignature.getParameterNames());
        List<Object> paramList = Arrays.asList(joinPoint.getArgs());

        //将方法的参数名和参数值一一对应的放入上下文中
        EvaluationContext ctx = new StandardEvaluationContext();
        for (int i = 0; i < paramNameList.size(); i++) {
            ctx.setVariable(paramNameList.get(i), paramList.get(i));
        }

        // 解析SpEL表达式获取结果
        Object value = spelParser.parseExpression(demo.spel()).getValue(ctx);
        if (value == null){
            return "";
        }else {
            return value.toString();
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

test测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class AppTest {

    @Autowired
    private Test2 test2;

    @Test
    public void test(){
        System.out.println(test2.test("张三"));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

AOP类将会输出 aop ===> 张三

# 4.spel常用语法

package org.example;

import org.example.aop.Test2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Arrays;

@RunWith(SpringRunner.class)
@SpringBootTest()
public class Test3 {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void test() {
        ExpressionParser parser = new SpelExpressionParser();

        // 括号优先,  #号读取 context 中的变量值, String 的方法全部可用 concat
        Expression expression = parser.parseExpression("('123' + ' 456').concat(#end)");
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("end", "789");
        System.out.println(expression.getValue(context)); //123 456789

        // 基本的计算 (+,-,*,/), 比较符号 ==, !=, "EQ” 、“NE”、 “GT”、“GE”、 “LT” 、“LE”
        expression = parser.parseExpression("(1+2) EQ #value");
        context = new StandardEvaluationContext();
        context.setVariable("value", 3);
        System.out.println(expression.getValue(context)); // true

        // 索引,截取
        expression = parser.parseExpression("'abcd'[1]");
        System.out.println(expression.getValue(context)); // b


        //三目运算及Elivis运算表达式, 等价写法
        expression = parser.parseExpression("#a != null?#a:'b'");
        //expression = parser.parseExpression("#a?:'b'");
        context = new StandardEvaluationContext();
        context.setVariable("a", null);
        System.out.println(expression.getValue(context)); // b

        // 正则表达式
        expression = parser.parseExpression("#name matches '\\d{3}'");
        context = new StandardEvaluationContext();
        context.setVariable("name", "123");
        System.out.println("正则 ==> " + expression.getValue(context)); // true

        // 赋值
        expression = parser.parseExpression("#user.name='bbb'");
        context = new StandardEvaluationContext();
        User user = new User("aaa");
        context.setVariable("user", user);
        expression.getValue(context);
        System.out.println("赋值 ==> " + user.getName()); // bbb

        // 实例化对象
        expression = parser.parseExpression("new org.example.User('bbb')");
        User value = (User) expression.getValue();
        System.out.println("实例化对象 ==> " + value.getName()); // bbb

        // 静态方法调用
        expression = parser.parseExpression("T(java.lang.Math).round(3.14)");
        System.out.println("静态方法调用 ==> " + expression.getValue()); // 3

        // Bean引用
        expression = parser.parseExpression("@test2.test('123')");
        context = new StandardEvaluationContext();
        context.setBeanResolver(new BeanFactoryResolver(applicationContext));
        System.out.println("Bean引用 ==> " + expression.getValue(context));  // OK

        // 集合, 过滤值大于4的
        expression = parser.parseExpression("#collection.?[#this>4]");
        context = new StandardEvaluationContext();
        context.setVariable("collection", Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));
        System.out.println("集合 ==> " + expression.getValue(context));  // [5, 6, 7, 8]
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

案例中用到的User类

package org.example;

/**
 * User
 *
 * @author 董新平
 * @since 2022/9/5 14:07
 */
public class User {

    public User(String name) {
        this.name = name;
    }

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

案例中的test2在3中已经声明

上次更新: 2023/06/12, 10:31:06
Bean创建三级缓存
Jackson自定义序列化字段

← Bean创建三级缓存 Jackson自定义序列化字段→

最近更新
01
Redis数据类型
01-20
02
Atomic
12-27
03
编译安装Redis
12-27
更多文章>
dongxinping | Copyright © 2022-2024 Dongxinping | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式