Aop切面编程(1)

1、aop的使用思想:面向切面的编程,不改变原有代码的基础上,进行拓展,减少代码的冗余,降低耦合性;

2、使用注解进行aop编程,使用自定义注解

2.1导入aop的依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.2新建注解类:TestCut

package com.example.demo.annotations;


import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestCut {

    String module() default "测试";

    String descript() default "描述";

}

2.3新建切面类:TestCutAspect

package com.example.demo.aop;

import com.example.demo.annotations.TestCut;
import com.example.demo.common.RestResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


@Component
@Aspect
public class TestCutAspect {

    @Pointcut("@annotation(com.example.demo.annotations.TestCut)")
    public void testCut(){

    }

    @Before("testCut()")
    public void beforeFun(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            System.out.println(arg.toString());
        }
        //请注意,这种修改是在切面内部进行的,不会影响原始方法中的参数值。
        // 如果你想要修改的是传入原方法的实际参数,而不仅仅是在切面中使用的参数的副本,那么这种方式可能不适用,
        // 因为join point提供的参数是只读的。在这种情况下,你可能需要考虑使用@Around建议来完全控制方法的执行,包括参数的传递。
        args[0]="789";
        System.out.println("注解方式AOP开始拦截, 当前拦截的方法名: " + method.getName());
    }

    @After("testCut()")
    public void afterFun(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        System.out.println("注解方式AOP执行的方法 :" + method.getName() + " 执行完了");
    }


    //1、注意一定要将@Around修饰的方法用Object修饰其返回值,并且返回原方法执行的结果。
    //2、@Around比较万能,尤其是配合ProceedingJoinPoint的使用。使AOP能做的事情更多了。
    //3、@Around如果不执行proceed(),那么原方法将不会执行
    //4、ProceedingJoinPoint 只能在@Around中使用
    @Around("testCut()")
    public Object testCutAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("注解方式AOP拦截开始进入环绕通知.......");
        Object[] args = joinPoint.getArgs();
        //修改args的值,相当于篡改了原方法入参的参数值
        args[0] ="***";
        //获取注解属性
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature =(MethodSignature)signature;
        Method method = methodSignature.getMethod();
        TestCut annotation = method.getAnnotation(TestCut.class);
        String descript = annotation.descript();
        String module = annotation.module();
        System.out.println(module+"|||"+descript);
        //执行原方法
        Object proceed = joinPoint.proceed(args);
        //修改proceed的值,相当于篡改了原方法执行完成之后的返回值
        proceed = RestResponse.error();
        System.out.println("准备退出环绕......");
        return proceed;
    }

    /**
     * returning属性指定连接点方法返回的结果放置在result变量中
     *
     * @param joinPoint 连接点
     * @param result    返回结果
     */
    @AfterReturning(value = "testCut()", returning = "result")
    public void afterReturn(JoinPoint joinPoint, Object result) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        System.out.println("注解方式AOP拦截的方法执行成功, 进入返回通知拦截, 方法名为: " + method.getName() + ", 返回结果为: " + result.toString());
    }

    @AfterThrowing(value = "testCut()", throwing = "e")
    public void afterThrow(JoinPoint joinPoint, Exception e) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        System.out.println("注解方式AOP进入方法异常拦截, 方法名为: " + method.getName() + ", 异常信息为: " + e.getMessage());
    }

}

2.4新建测试类,在需要切面的方法添加注解@TestCut(module = "测试aop",descript = "我是aop的描述属性")

@RestController
@RequestMapping("/aop")
public class AopRestController {

    @RequestMapping("/test")
    @TestCut(module = "测试aop",descript = "我是aop的描述属性")
    public RestResponse test(String aaa,String bbb){
        System.out.println("我是test方法");
        String c = aaa+bbb;
        return RestResponse.successMsg(c);
    }
}

2.5定义统一返回结果

package com.zlkj.file.exception;

import io.swagger.annotations.ApiModelProperty;

/**
 * @author ycy
 */

public class RestResponse {

    @ApiModelProperty(
            name = "success",
            value = "是否成功",
            required = true,
            dataType = "Boolean"
    )
    private Boolean success;

    @ApiModelProperty(
            name = "data",
            value = "返回结果",
            required = false,
            dataType = "Object"
    )
    private Object data;

    @ApiModelProperty(
            name = "msg",
            value = "提示信息",
            required = false,
            dataType = "String"
    )
    private String msg;

    public RestResponse(Boolean success, String msg, Object data){
        this.success = success;
        this.msg = msg;
        this.data = data;
    }

    public static RestResponse success(){
        return new RestResponse(true, null,null);
    }

    public static RestResponse error(){
        return new RestResponse(false, null, null);
    }

    public static RestResponse successMsg(String msg){
        return new RestResponse(true, msg, null);
    }

    public static RestResponse errorMsg(String msg){
        return new RestResponse(false, msg, null);
    }

    public static RestResponse successResult(String msg, Object data){
        return new RestResponse(true, msg, data);
    }

    public static RestResponse errorResult(String msg, Object data){
        return new RestResponse(false, msg, data);
    }

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "RestResponse{" +
                "success=" + success +
                ", data=" + data +
                ", msg='" + msg + '\'' +
                '}';
    }
}

3、项目结构

4、执行接口

5、通过测试发现常用的aop注解的执行顺序,around包在最外侧;
@around-方法前

@before

@afterReturning

@after

@around-方法后

有异常:

无异常:

通过测试看就是:

1、afterReturning和afterThrow是互斥的二选一;
2、after一定会执行,around后置方法在抛出异常之后不会执行了;

6、around可以修改入参、出参的值;

注意一定要将@Around修饰的方法用Object修饰其返回值,并且返回原方法执行的结果。
 @Around比较万能,尤其是配合ProceedingJoinPoint的使用。使AOP能做的事情更多了。
 @Around如果不执行proceed(),那么原方法将不会执行
 ProceedingJoinPoint 只能在@Around中使用

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值