spring boot AOP @Before @After 最簡單的切面


寫一個最簡單明細的切面,希望可以復制了直接用。我會盡量把注釋寫詳細

1.引入jar
因為我是用的springboot,所以只需要引入一個包,如果你習慣的是引入兩個包 也可以引入下面的兩個包
SpingBoot:

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

Spring:

<!--aop切面-->
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
</dependency>

2.切面類
作用:可以做登錄攔截或者參數攔截
首先新建一個.java文件,在類上加上@Component和@Aspect 注解

@Component 	//把切面類加入到IOC容器中 
@Aspect		//使之成為切面類
@Order(1)	//如果有多個 可以定義來控制順序 數字越小執行順序靠前
public class AopHandlerAspect {
	//日志 我是使用的hutool中的日志方法 你可以改為你自己的
    private Log logger = LogFactory.get();
	
	//為了記錄執行時間 方便調試 如果不需要可以去掉
    ThreadLocal<Long> startTime = new ThreadLocal<>();

	//定義一個切入點 我這里是從controller切入 不是從注解切入
	//詳情看下方的 切入點表達式
    @Pointcut("execution(public * cn.o.generate.controller.*.*(..))")
    public void pointCut() {}
	
	//在進入方法前執行 可以對參數進行限制或者攔截
	//通常在這邊做日志存儲存到數據庫中
    @Before("pointCut()")
    public void before(JoinPoint joinPoint) throws Throwable {
        logger.info("==================前置執行=====================>");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        logger.info("請求來源: =》" + request.getRemoteAddr());
        logger.info("請求URL:" + request.getRequestURL().toString());
        logger.info("請求方式:" + request.getMethod());
        logger.info("響應方法:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("請求參數:" + Arrays.toString(joinPoint.getArgs()));
        logger.info("==================前置執行完成==================>");
        startTime.set(System.currentTimeMillis());
    }
//環繞執行
//定義需要匹配的切點表達式,同時需要匹配參數
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        StaticLog.info("==================方法環繞前置start=====================>");
        //這句必須有 往下執行方法
        Object result = pjp.proceed();

        StaticLog.info("==================方法環繞后置start=====================>");
        StaticLog.info("耗時(毫秒):" + time);
        StaticLog.info("返回數據:{}", result);
        StaticLog.info("==================方法環繞end======================>");
        return result;
    }

	//在方法執行后執行 可以打印返回的數據 判斷數據是否是自己需要的
    @After("pointCut()")
    public void after(JoinPoint point) {
        if (startTime.get() == null) {
            startTime.set(System.currentTimeMillis());
        }
        logger.info("==================后置執行======================>");
        logger.info("耗時(毫秒):" + (System.currentTimeMillis() - startTime.get()));
        logger.info("返回數據:{}", point.getArgs());
        logger.info("==================后置執行完成==================>");
    }
}

切入點表達式

定義切入點的時候需要一個包含名字和任意參數的簽名,還有一個切入點表達式,如execution(public * com.example.aop...(..))

切入點表達式的格式:execution([可見性]返回類型[聲明類型].方法名(參數)[異常]) 
其中[]內的是可選的,其它的還支持通配符的使用: 
1) *:匹配所有字符 
2) ..:一般用於匹配多個包,多個參數 
3) +:表示類及其子類 
4)運算符有:&&,||,!

切入點表達式關鍵詞用例: 
1)execution:用於匹配子表達式。 
//匹配com.cjm.model包及其子包中所有類中的所有方法,返回類型任意,方法參數任意 
@Pointcut(“execution(* com.cjm.model...(..))”) 
public void before(){}

2)within:用於匹配連接點所在的Java類或者包。 
//匹配Person類中的所有方法 
@Pointcut(“within(com.cjm.model.Person)”) 
public void before(){} 
//匹配com.cjm包及其子包中所有類中的所有方法 
@Pointcut(“within(com.cjm..*)”) 
public void before(){}

3) this:用於向通知方法中傳入代理對象的引用。 
@Before(“before() && this(proxy)”) 
public void beforeAdvide(JoinPoint point, Object proxy){ 
//處理邏輯 
}

4)target:用於向通知方法中傳入目標對象的引用。 
@Before(“before() && target(target) 
public void beforeAdvide(JoinPoint point, Object proxy){ 
//處理邏輯 
}

5)args:用於將參數傳入到通知方法中。 
@Before(“before() && args(age,username)”) 
public void beforeAdvide(JoinPoint point, int age, String username){ 
//處理邏輯 
}

6)@within :用於匹配在類一級使用了參數確定的注解的類,其所有方法都將被匹配。 
@Pointcut(“@within(com.cjm.annotation.AdviceAnnotation)”) 
- 所有被@AdviceAnnotation標注的類都將匹配 
public void before(){}

7)@target :和@within的功能類似,但必須要指定注解接口的保留策略為RUNTIME。 
@Pointcut(“@target(com.cjm.annotation.AdviceAnnotation)”) 
public void before(){}

8)@args :傳入連接點的對象對應的Java類必須被@args指定的Annotation注解標注。 
@Before(“@args(com.cjm.annotation.AdviceAnnotation)”) 
public void beforeAdvide(JoinPoint point){ 
//處理邏輯 
}

9)@annotation :匹配連接點被它參數指定的Annotation注解的方法。也就是說,所有被指定注解標注的方法都將匹配。 
@Pointcut(“@annotation(com.cjm.annotation.AdviceAnnotation)”) 
public void before(){}

10)bean:通過受管Bean的名字來限定連接點所在的Bean。該關鍵詞是Spring2.5新增的。 
@Pointcut(“bean(person)”) 
public void before(){}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM