day8 AOP 面向切面编程

AOP即是一种编程范式,指导对类中的方法进行效果增强

比如我们要对类中的某些方法增加一个性能检测方法,这时我们不需要在一个个方法中进行代码添加,我们可以利用AOP技术进行批量的效果增加

下面以一个入门案例为例

增强的功能:在接口方法 执行前打印系统时间

1.导入aop相关坐标

<dependencies>
  <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>
</dependencies>

2.定义dao接口和实现类

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao {

    public void save() {
        //记录程序当前执行执行(开始时间)
        Long startTime = System.currentTimeMillis();
        //业务执行万次
        for (int i = 0;i<10000;i++) {
            System.out.println("book dao save ...");
        }
        //记录程序当前执行时间(结束时间)
        Long endTime = System.currentTimeMillis();
        //计算时间差
        Long totalTime = endTime-startTime;
        //输出信息
        System.out.println("执行万次消耗时间:" + totalTime + "ms");
    }

    public void update(){
        System.out.println("book dao update ...");
    }

    public void delete(){
        System.out.println("book dao delete ...");
    }

    public void select(){
        System.out.println("book dao select ...");
    }
}

3.定义通知

public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("------------------------------");
        Long startTime = System.currentTimeMillis();
        for (int i = 0 ; i<10000 ; i++) {
            //调用原始操作
            pjp.proceed();
        }
        Long endTime = System.currentTimeMillis();
        Long totalTime = endTime-startTime;
        System.out.println("执行万次消耗时间:" + totalTime + "ms");
        return null;
    }

4.定义切入点和切面来绑定关系

注意要在配置文件中引入下面注解来激活aopp

@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy

package com.itheima.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


@Component
@Aspect//AOP注解,向框架表明使用了aop
public class MyAdvice {

    @Pointcut("execution(* com.itheima.dao.BookDao.*d*(..))")
    private void pt(){}//切入点

    @Around("pt()")//切面注解,表明位置是around,也可以改为before,在切入点之前执行
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("------------------------------");
        Long startTime = System.currentTimeMillis();
        for (int i = 0 ; i<10000 ; i++) {
            //调用原始操作
            pjp.proceed();
        }
        Long endTime = System.currentTimeMillis();
        Long totalTime = endTime-startTime;
        System.out.println("执行万次消耗时间:" + totalTime + "ms");
        return null;
    }

}

至此,功能增加完成

注意,因为aop工作流程是代理模式,当切面与切入点可以匹配时,开启代理模式,使用的是代理对象进行业务执行。而不匹配时,使用目标对象进行业务执行

AOP切入点表达式

即是匹配被增强的方法的表达式

比如

@Pointcut("execution(* com.itheima.dao.BookDao.*d*(..))")

这里可以使用通配符来进行简化表达式子

AOP通知类型

这里主要讨论AOP通知类型的通知位置---前置,后置,环绕(重点)等

@Around("pt()")//切面注解,表明位置是around,也可以改为before,在切入点之前执行
public Object around(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("------------------------------");
    Long startTime = System.currentTimeMillis();
    for (int i = 0 ; i<10000 ; i++) {
        //调用原始操作
        pjp.proceed();
    }
    Long endTime = System.currentTimeMillis();
    Long totalTime = endTime-startTime;
    System.out.println("执行万次消耗时间:" + totalTime + "ms");
    return null;
}

pjp.proceed方法就是调用了原方法,这样可以表示环绕的形式

注意:如果原方法有返回值,则必需接收并抛出返回值,object ret=pjp.proceed(),且在方法头中加入throw字段进行抛出

案例:测试接口万次执行效率

主要关注切入点和切面

package com.itheima.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class ProjectAdvice {
    //匹配业务层的所有方法
    @Pointcut("execution(* com.itheima.service.*Service.*(..))")
    private void servicePt(){}

    //设置环绕通知,在原始操作的运行前后记录执行时间
    @Around("ProjectAdvice.servicePt()")
    public void runSpeed(ProceedingJoinPoint pjp) throws Throwable {
        //获取执行的签名对象
        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");
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值