欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义注解结合切面和spel表达式

程序员文章站 2022-04-05 21:09:58
...

    在我们的实际开发中可能存在这么一种情况,当方法参数中的某些条件成立的时候,需要执行一些逻辑处理,比如输出日志。而这些代码可能都是差不多的,那么这个时候就可以结合自定义注解加上切面加上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表达式
            
    
    博客分类: spring springspelannotationaspect 

三、写一个自定义切面

    注意一下解析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>

 五、测试。
    自定义注解结合切面和spel表达式
            
    
    博客分类: spring springspelannotationaspect 

 

六、增加内容:

1、当我们想在自己写的spel表达式中调用spring bean 管理的方法时,如何写。spel表达式支持使用 @来引用bean,但是此时需要注入BeanFactory
自定义注解结合切面和spel表达式
            
    
    博客分类: spring springspelannotationaspect 
 

 


 
 

  • 自定义注解结合切面和spel表达式
            
    
    博客分类: spring springspelannotationaspect 
  • 大小: 38.6 KB
  • 自定义注解结合切面和spel表达式
            
    
    博客分类: spring springspelannotationaspect 
  • 大小: 130.9 KB
  • 自定义注解结合切面和spel表达式
            
    
    博客分类: spring springspelannotationaspect 
  • 大小: 21.8 KB