Spring AOP实现自定义注解

自定义注解与AOP实战
本文介绍如何创建自定义注解并结合Spring AOP进行应用。通过定义注解、配置切面类以及在控制器中使用注解,实现方法执行前后的日志记录功能。

前言:鉴于前两天面试,让实现一个自定义注解的面试题卡住,及扩展Spring注解怎么实现的问题。在此先把实现自定义注解这部分,把以前代码中写过的一个简单的例子,记录一下。

1、定义一个自定义注解

package com.example.demo.aop;

import java.lang.annotation.*;

/**
 * @author jushisi
 * @description 自定义注解用于AOP拦截标识
 */
@Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时依然存在
@Target(ElementType.METHOD)
@Documented
public @interface AopLog {

}

2、AOP读取注解,做具体操作

利用@annotation(com.example.demo.aop.AopLog)读取

package com.example.demo.aop;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSON;

/**
 * @author jushisi
 * @description TODO AOP为啥不能成功调用所有方法 有点奇怪 待研究
 */
@Component
@Aspect
public class HttpAspect {

    private static final Logger logger = LoggerFactory.getLogger(HttpAspect.class);

//    @Pointcut("execution(* com.example.demo.controller..*.*(..)) && @annotation(com.example.demo.aop.AopLog)")
    @Pointcut("@annotation(com.example.demo.aop.AopLog)")
    public void log(){
    }

    /**
     * @description 注意使用ProceedingJoinPoint proceed()
     * @author jushisi
     */
    @Around("log()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info("@Around:在建议方法调用之前和之后,执行通知。");
        joinPoint.proceed();
        logger.info("@Around:在建议方法调用之前和之后,执行通知。");
    }

    /**
     * @description 没有环绕通知时 调用
     * @author jushisi
     */
    @Before("log()")
    public void before(JoinPoint joinPoint){
        ServletRequestAttributes attributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request =attributes.getRequest();
        logger.info("@Before:在一个方法执行之前,执行通知。");
    }

    /**
     * @description 没有环绕通知时 调用
     * @author jushisi
     */
    @After("log()")
    public void after(){
        logger.info("@After:在一个方法执行之后,不考虑其结果,执行通知。");
    }

    /**
     * @description 没有环绕通知时 方法执行成功时调用
     * @author jushisi
     */
    @AfterReturning(pointcut = "log()",returning = "obj")
    public void afterReturning(Object obj){
        logger.info("@AfterReturning:在一个方法执行之后,只有在方法成功完成时,才能执行通知。");
        logger.info("@AfterReturning:"+ JSON.toJSONString(obj));
    }

    /**
     * @description 没有环绕通知时,抛异常时调用 ; 有环绕通知时,即使抛异常也不调用
     * @author jushisi
     */
    @AfterThrowing(pointcut = "log()", throwing = "ex")
    public void afterThrowing(Exception ex){
        logger.info("@AfterThrowing:在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。");
    }
}

3、调用注解的地方

package com.example.demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.aop.AopLog;

/**
 * @author jushisi
 * @description AopTest
 */
@RestController
@RequestMapping("/aop")
public class AopTest {

    private static final Logger logger = LoggerFactory.getLogger(AopTest.class);

    @RequestMapping("/exception")
    @AopLog
    public String  exception(Integer num){
        logger.info(String.valueOf(1/num));
        return "exception";
    }

    @RequestMapping("/test")
    @AopLog
    public String  test(Integer num){
        String str = "AOP function test ......";
        logger.info(str);
        return str;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值