SSM学习——AOP(8)

16 篇文章 1 订阅

简介

在这里插入图片描述

原本的功能都称为连接点
需要追加功能的方法称为切入点
需要追加的功能称为通知
对应包裹着的类称为通知类
一个通知对应的切入点称为切面

在这里插入图片描述
在这里插入图片描述

案例

在这里插入图片描述

在dao层有2个方法
在这里插入图片描述

配置类也很简单
在这里插入图片描述

现在我使用save方法会打印出时间
在这里插入图片描述

而使用update不会打印出时间
在这里插入图片描述

我们的任务是,当我们执行update时,需要有时间输出,而且还不能改动原本业务

1导包

由于spring-aop是在spring-context里面的默认导入,所以我们只要导入aspect即可

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
<dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>

2抽取共性功能

创建aop包与class
在这里插入图片描述

在里面定义我们的共性功能

public void method(){
        System.out.println(System.currentTimeMillis());
    }

然后增加功能

//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类,告诉spring扫描到我之后把我当aop处理
@Aspect
public class MyAdvice {
    //设置切入点,要求配置在方法上方 括号内为此方法的返回值,路径与传入参数
    @Pointcut("execution(void com.itheima.dao.BookDao.update())")
    //建造一个空壳
    private void pt(){}

    //设置在切入点pt()的前面运行当前操作(前置通知)
     @Before("pt()")
    public void method(){
        System.out.println(System.currentTimeMillis());
    }
}

在SpringConfig核心配置类里告诉spring启动aop编程

@EnableAspectJAutoProxy

主函数类里面启动一下切入点方法即可发现成功执行aop

在这里插入图片描述在这里插入图片描述

总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

AOP工作流程

在这里插入图片描述

在这里插入图片描述

AOP切入点表达式

在这里插入图片描述

execution这个词基本不会变化
public一般都省略,默认了
User返回值,需要返回的值自己写

在这里插入图片描述

但是如果一个程序中开发了几百个上千个功能,那么肯定要写死了
所以我们希望写一个,能代表一堆,因此,通配符就出来了

在这里插入图片描述
在这里插入图片描述

这里需要注意的是,当最后的方法里面写了*时,代表着里面必须有形参,而不是可以没有!
以后的aop都是这么写的:
①我要给所有业务层的find方法加上aop:@Pointcut("execution(* it.calendo.*.*Service.find*(..))")

在这里插入图片描述

通知类型

在这里插入图片描述
案例:

@Component
@Aspect
public class MyAdvice {
    @Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private void pt() {
    }

    @Pointcut("execution(int com.itheima.dao.BookDao.select())")
    private void pt2() {
    }

    //@Before:前置通知,在原始方法运行之前执行
//    @Before("pt()")
    public void before() {
        System.out.println("before advice ...");
    }

    //@After:后置通知,在原始方法运行之后执行
//    @After("pt2()")
    public void after() {
        System.out.println("after advice ...");
    }

    //@Around:环绕通知,在原始方法运行的前后执行
    @Around("pt2()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        //表示对原始操作的调用(强制抛异常)
        Object ret = pjp.proceed();
        System.out.println("around after advice ...");
        return ret;
    }

    //    @Around("pt2()")
    public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        //表示对原始操作的调用
        Integer ret = (Integer) pjp.proceed();
        System.out.println("around after advice ...");
        return ret;
    }

    //@AfterReturning:返回后通知,在原始方法执行完毕后运行,且原始方法执行过程中未出现异常现象
//    @AfterReturning("pt2()")
    public void afterReturning() {
        System.out.println("afterReturning advice ...");
    }

    //@AfterThrowing:抛出异常后通知,在原始方法执行过程中出现异常后运行
//    @AfterThrowing("pt2()")
    public void afterThrowing() {
        System.out.println("afterThrowing advice ...");
    }
}

在这里插入图片描述
在这里插入图片描述

proceedingJoinPoint如果没有执行对原始方法的调用,就会产生一种隔离效果,可以用来进行身份校验

签名

签名即是对原始数据的一种封装,我们可以在aop编程中获取到签名内部的指定信息

首先去核心配置类里注册一下@EnableAspectJAutoProxy开启aop

@Component
@Aspect
public class Service_10K_speedtest {
    //    匹配业务层的所有方法
    @Pointcut("execution(* cn.calendo.service.*Service.*(..))")
    private void ServicePt() {
    }

    @Around("Service_10K_speedtest.ServicePt()")
    public void runspeed(ProceedingJoinPoint pjp) throws Throwable {
        //Signature是我们执行时候封装的签名,通过签名可以获取接口名与方法名
        //获取执行签名信息
        Signature signature = pjp.getSignature();
        //通过签名获取执行类型(接口名)
        String className = signature.getDeclaringTypeName();
        //通过签名获取执行操作名称(方法名)
        String methodName = signature.getName();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            pjp.proceed();
        }
        long end = System.currentTimeMillis();
        System.out.println("万次执行" + className + "." + methodName + "---->" + (end - start) + "ms");
    }
}

在这里插入图片描述

AOP通知获取数据

在这里插入图片描述

//JoinPoint:用于描述切入点的对象,必须配置成通知方法中的第一个参数,可用于获取原始方法调用的参数
    @Before("pt()")
    //使用JoinPoint去获取原方法对象
    public void before(JoinPoint jp) {
        //getArgs去原方法里面拿数组形式的参数
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("before advice ...");
    }

    @After("pt()")
    public void after(JoinPoint jp) {
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("after advice ...");
    }

在这里插入图片描述

在这里插入图片描述

百度网盘提取码实例

因为提取码是末尾带空格的,所以需要trim()一下
在这里插入图片描述

我们先写好提取码的接收与匹配(假设是固定的root
我们在主函数类里面接收到提取码(他是带首尾空格的,因此会不匹配)

public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        ResourcesService resourcesService = ctx.getBean(ResourcesService.class);
        boolean flag = resourcesService.openURL("http://pan.baidu.com/haha", "  root ");
        System.out.println(flag);
    }
}

然后我们看下初始的执行流程
dao层里面用来匹配提取码
在这里插入图片描述

我们的目标很明确,就是去新建一个aop来对这个原始的业务进行增强
我们新建一个aop类
在这里插入图片描述

然后注册一下@Compnent注解开发组件与@AspectAOP标签
然后再定义一个空函数作为锚点

public void servicePt() {
    }

在其之上定位到切入点进行加强方法

@Pointcut("execution(boolean com.itheima.service.ResourcesService.openURL(..))")

接下来写我们的aop方法

//使用环绕型以及servicePt锚点
    @Around("Trim_Checked.servicePt()")
    //由于我们需要原始数据的返回值进行处理,所以需要用到pjp
    public Object trimPwd(ProceedingJoinPoint pjp) throws Throwable {
        //获取数组形式参数
        Object[] args = pjp.getArgs();
        //for循环对参数进行匹配和trim
        for (int i = 0; i < args.length; i++) {
            //判断参数是不是字符串
            if (args[i].getClass().equals(String.class)) {
                //将改变的内容重新放回去
                args[i] = args[i].toString().trim();
            }
        }
        //作为object返回出去即可
        Object ret = pjp.proceed(args);
        return ret;
    }

在这里插入图片描述

如果有相同的大量的业务需要同时添加的话,那么AOP将是不二之选!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值