在我们的实际开发中可能存在这么一种情况,当方法参数中的某些条件成立的时候,需要执行一些逻辑处理,比如输出日志。而这些代码可能都是差不多的,那么这个时候就可以结合自定义注解加上切面加上spel表达式进行处理。就比如在spring中我们可以使用@Cacheable(key="#xx")实现缓存,这个#xx就是一个spel表达式。

需求:我们需要将service层方法中方法的某个参数的值大于0.5的方法,输出方法执行日志。(需要了解一些spel表达式的语法)

实现步骤

1、自定义一个注解Log

2、自定义一个切面,拦截所有方法上存在@Log注解修饰的方法

3、写一个service层方法,方法上标注@Log注解

难点

在切面中需要拿到具体执行方法的方法名,可以使用spring提供的LocalVariableTableParameterNameDiscoverer来获取到

一、自定义一个注解

注意:注解中的spel的值是必须的,且spel表达式返回的结果应该是一个布尔值

/**
* 记录日志信息,当spel表但是中的值为true时,输出日志信息
*
* @描述
* @作者 huan
* @时间 2017年10月2日 - 上午10:25:39
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String spel();
String desc() default "描述";
}

二、自定义一个service类,在需要拦截的方法上加上@Log注解
   

三、写一个自定义切面

注意一下解析spel表达式中context的设值即可

/**
* 日志切面,当条件满足时输出日志.
*
* @描述
* @作者 huan
* @时间 2017年10月2日 - 上午10:32:16
*/
@Component
@Aspect
public class LogAspect {
ExpressionParser parser = new SpelExpressionParser();
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
@Around("@annotation(log)")
public Object invoked(ProceedingJoinPoint pjp, Log log) throws Throwable {
Object[] args = pjp.getArgs();
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
String spel = log.spel();
String[] params = discoverer.getParameterNames(method);
EvaluationContext context = new StandardEvaluationContext();
for (int len = 0; len < params.length; len++) {
context.setVariable(params[len], args[len]);
}
Expression expression = parser.parseExpression(spel);
if (expression.getValue(context, Boolean.class)) {
System.out.println(log.desc() + ",在" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "执行方法," + pjp.getTarget().getClass() + "." + method.getName()
+ "(" + convertArgs(args) + ")");
}
return pjp.proceed();
}
private String convertArgs(Object[] args) {
StringBuilder builder = new StringBuilder();
for (Object arg : args) {
if (null == arg) {
builder.append("null");
} else {
builder.append(arg.toString());
}
builder.append(',');
}
builder.setCharAt(builder.length() - 1, ' ');
return builder.toString();
}
}

四、pom文件的依赖

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

五、测试。
   

六、增加内容:

1、当我们想在自己写的spel表达式中调用spring bean 管理的方法时,如何写。spel表达式支持使用 @来引用bean,但是此时需要注入BeanFactory

自定义注解结合切面和spel表达式的更多相关文章

  1. 010-Spring aop 001-核心说明-拦截指定类与方法、基于自定义注解的切面

    一.概述 面向切面编程(AOP)是针对面向对象编程(OOP)的补充,可以非侵入式的为多个不具有继承关系的对象引入相同的公共行为例如日志.安全.事务.性能监控等等.SpringAOP允许将公共行为从业务 ...

  2. Spring自定义注解配置切面实现日志记录

    一: spring-mvc.xml: <!--配置日志切面 start,必须与mvc配置在同一个配置文件,否则无法切入Controller层--><!-- 声明自动为spring容器 ...

  3. 使用自定义注解和切面AOP实现Java程序增强

    1.注解介绍 1.1注解的本质 Oracle官方对注解的定义为: Annotations, a form of metadata, provide data about a program that ...

  4. 用AOP拦截自定义注解并获取注解属性与上下文参数(基于Springboot框架)

    目录 自定义注解 定义切面 获取上下文信息JoinPoint ProceedingJoinPoint 定义测试方法 测试结果 小结 AOP可以用于日志的设计,这样话就少不了要获取上下文的信息,博主在设 ...

  5. spring boot通过自定义注解和AOP拦截指定的请求

    一 准备工作 1.1 添加依赖 通过spring boot创建好工程后,添加如下依赖,不然工程中无法使用切面的注解,就无法对制定的方法进行拦截 <dependency> <group ...

  6. 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  7. redis缓存切面实现(支持缓存key的spel表达式)

    1.定义注解 package com.g2.order.server.annotation; import java.lang.annotation.ElementType; import java. ...

  8. Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志

    其实,小哈在之前就出过一篇关于如何使用 AOP 切面统一打印请求日志的文章,那为什么还要再出一篇呢?没东西写了? 哈哈,当然不是!原因是当时的实现方案还是存在缺陷的,原因如下: 不够灵活,由于是以所有 ...

  9. Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId

    一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...

随机推荐

  1. Vue跨域问题解决

    项目根目录下创建vue.config.js module.exports = { devServer: { proxy: { //配置跨域 '/api': { //这里是真实的后台接口 target: ...

  2. Stream流思想和常用方法

    一.IO流用于读写:Stream流用于处理数组和集合数据: 1.传统集合遍历: 2.使用Stream流的方式过滤: 其中,链式编程(返回值就是对象自己)中,filter使用的是Predicate函数式 ...

  3. MySQL(3)-日志

    3. InnoDB日志 3.1 InnoDB架构 分为 内存区域架构 buffer pool log buffer 磁盘区域架构 redo log undo log 2.1.1 内存区域架构 1)Bu ...

  4. 数据库实验sql代码 myemployees 以及mygirl

    /* Navicat Premium Data Transfer Source Server : mysql Source Server Type : MySQL Source Server Vers ...

  5. python win32com 处理excle 写一个公共的类

    利用win32com处理excle,这样可以不管文件是老的xls还是新的xlsx格式,非常方便. 类的源码如下: import win32com.client as win32 class easyE ...

  6. POJ3625Building Roads

    Building Roads Description Farmer John had just acquired several new farms! He wants to connect the ...

  7. dedecms内页调用内容当中第一张图片

    在includes/extend.func.php末尾添加方法: //取第一张图地址 function firstimg($str_pic) { $str_sub=substr($str_pic,0, ...

  8. CLion远程调试嵌入式开发板程序

    CLion远程调试嵌入式开发板程序 目录 CLion远程调试嵌入式开发板程序 1. 目的 2. 前提条件 3. CLion设置 3.1 设置一个Deployment 3.2 上传需要的目录到目标板子 ...

  9. 我是小白,做PPT像流水账,怎么做一份重点突出的PPT?

    1.PPT的封面不要只写标题,还要在显眼的位置写上你的核心观点.比如,你之前做的PPT封面标题是<A产品市场前景分析>,现在不妨加上一个副标题<红海市场中需要找到更多本产品卖点> ...

  10. P1251-餐巾计划问题【费用流】

    正题 题目链接:https://www.luogu.com.cn/problem/P1251 题目大意 \(N\)天,第\(i\)天需要\(a_i\)个餐巾. 每个餐巾价格为\(p\),使用完后有两种 ...