注解实现spring AOP
1、前言
实现spring AOP有3种方式:①spring接口实现;②自定义类实现;③注解实现。本篇主要记录第三种方式,它也是最常用的。
2、导包
虽然aop包中提供了AOP功能,但是它是依赖aspectj来实现的。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
3、注解实现aop
首先开启注解@EnableAspectJAutoProxy
package com.zhengx.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
//排除security安全验证
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
//@SpringBootApplication
//ElasticsearchRepository的路径
@EnableElasticsearchRepositories(basePackages = "com.zhengx.study.elasticsearch.repository")
//自动为匹配的类生成代理对象
@EnableAspectJAutoProxy
public class StudyApplication {
public static void main(String[] args) {
SpringApplication.run(StudyApplication.class, args);
}
}
接着自定义注解
package com.zhengx.study.elasticsearch.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogJei {
String value() default "";
}
然后实现切面逻辑(有五种advice)
package com.zhengx.study.elasticsearch.common;
import com.alibaba.excel.util.StringUtils;
import com.zhengx.study.elasticsearch.annotation.LogJei;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Objects;
@Component
@Aspect
@Slf4j
public class MyAspect {
/**
* 配置切入点
*/
@Pointcut("@annotation(com.zhengx.study.elasticsearch.annotation.LogJei)")
public void logPointcut() {
//该方法无方法体,主要为了让同类中其他方法使用此切入点
}
@Before("logPointcut()")
public void beforeMethod() {
System.out.println("前置通知");
System.out.println("--------------------------------------");
}
@After("logPointcut()")
public void afterMethod() {
System.out.println("后置通知");
System.out.println("--------------------------------------");
}
@AfterReturning("logPointcut()")
public void afterReturningMethod() {
System.out.println("返回结果之后通知");
System.out.println("--------------------------------------");
}
@AfterThrowing("logPointcut()")
public void afterThrowingMethod() {
System.out.println("抛出异常后通知");
System.out.println("--------------------------------------");
}
@Around("logPointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
//获取注解参数值
LogJei logJei = methodSignature.getMethod().getAnnotation(LogJei.class);
String value = logJei.value();
// 通过joinPoint获取被注解方法
String id = generateKeyByStr(value, pjp);
//获取id
System.out.println("环绕通知around before");
System.out.println("--------------------------------------");
Object ret = pjp.proceed();
//获取id
System.out.println(" 环绕通知around after");
System.out.println("--------------------------------------");
return ret;
}
private String generateKeyByStr(String str, ProceedingJoinPoint pjp) {
if (StringUtils.isBlank(str)) {
return null;
}
// 通过joinPoint获取被注解方法
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
//创建解析器
SpelExpressionParser parser = new SpelExpressionParser();
//获取表达式
Expression expression = parser.parseExpression(str);
//设置解析上下文(有哪些占位符,以及每种占位符的值)
EvaluationContext context = new StandardEvaluationContext();
//获取参数值
Object[] args = pjp.getArgs();
//获取运行时参数的名称
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] parameterNames = discoverer.getParameterNames(method);
for (int i = 0; i < Objects.requireNonNull(parameterNames).length; i++) {
context.setVariable(parameterNames[i], args[i]);
}
//解析,获取替换后的结果
String result = expression.getValue(context).toString();
System.out.println(result);
return result;
}
}
最后应用
package com.zhengx.study.elasticsearch.controller;
import com.zhengx.study.elasticsearch.annotation.LogJei;
import com.zhengx.study.elasticsearch.entity.doc.UserInfoDoc;
import com.zhengx.study.elasticsearch.common.Result;
import com.zhengx.study.elasticsearch.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author jiangl
* @ClassName UserInfoController.java
* @Description
* @createTime 2021年10月18日 16:52
*/
@RestController
@RequestMapping("/userInfo")
@Slf4j
public class UserInfoController {
@Resource
private UserInfoService userInfoService;
@LogJei(value = "#id") //获取参数,get和post有不同
@GetMapping("/findOne")
public Result<?> findOne(int id) {
UserInfoDoc userInfoDoc = userInfoService.findOne(id);
return Result.succeed(userInfoDoc, "ok");
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结