注解实现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");
    }
}
posted @   南翔技校毕业后  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结
点击右上角即可分享
微信分享提示