springboot中AOP总结

1.AOP工作流程

在这里插入图片描述

2.AOP概述

AOP(Aspect Orient Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程(OOP)的一种补充和完善。实际项目中我们通常将面向对象理解为一个静态过程(例如一个系统有多少个模块,一个模块有哪些对象,对象有哪些属性),面向切面理解为一个动态过程(在对象运行时动态织入一些扩展功能或控制对象执行)。如图所示:

在这里插入图片描述  

3.实现原理

AOP可以在系统启动时为目标类型创建子类或兄弟类型对象,这样的对象我们通常会称之为动态代理对象.如图所示:

在这里插入图片描述

其中,为目标类型(XxxServiceImpl)创建其代理对象方式有两种(先了解):

第一种方式:借助JDK官方API为目标对象类型创建其兄弟类型对象,但是目标对象类型需要实现相应接口.
第二种方式:借助CGLIB库为目标对象类型创建其子类类型对象,但是目标对象类型不能使用final修饰.

4.AOP使用流程

        1.添加aop依赖

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

说明:基于此依赖spring可以整合AspectJ框架快速完成AOP的基本实现。AspectJ 是一个面向切面的框架,他定义了 AOP 的一些语法,有一个专门的字节码生成器来生成遵守 java 规范的 class 文件。

        2.创建注解类型,应用于切入点表达式的定义,关键代码如下: 

package com.jt.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredLog {
    String operation() default "";
}

        3.创建切面对象,用于做日志业务增强,关键代码如下:

package com.jt.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;

/**
 * @Aspect注解描述的类我们称之为切面对象,此对象负责定义切入点和通知
 * 1)切入点(在哪些方法执行时我们进行功能扩展-锦)
 * 2)通知(所有的扩展逻辑都会写到通知方法中-花)
 */
@Aspect
@Component
public class LogAspect {
    /**
     * 通过@Pointcut注解定义定义切入点表达式,表达式的写法有多种,比较常用
     * 有注解方式的表达式(@annotation(你自己定义的注解)).当使用自己写
     * 的注解对方法进行描述时,这个方法就是切入点方法.在这个方法上要锦上添花
     */
    @Pointcut("@annotation(com.jt.aop.RequiredLog)")
    public void doLog(){}//这个方法没有意义,主要用于承载切入点

    /**
     * Around通知,在此通知内部可以定义我们扩展业务逻辑,还可以调用目标执行链
     * @param joinPoint 连接点(通知方法与目标方法的连接点对象),ProceedingJoinPoint
     *   类型的连接点只能应用在Around通知方法中.
     * @return
     * @throws Throwable
     */
    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint joinPoint)
    throws Throwable{
         System.out.println("Before:"+System.currentTimeMillis());
         Object result=joinPoint.proceed();//执行链(其它切面,目标对象方法)
         System.out.println("After:"+System.currentTimeMillis());
         return result;
    }

}

         4.通过注解RequiredLog注解描述日志查询或删除业务相关方法,此时这个方法为日志切入点方法,例如:

@RequiredLog(operation="公告查询")
@Override
public List<SysLog> findLogs(SysLog sysLog) {
List<SysLog> list=syslogDao.selectLogs(sysLog);
    return list;
}

        5.测试通知业务方法,并检测日志输出以及了解其运行原理,如图所示:

在这里插入图片描述5.AOP进阶技术

Spring框架AOP模块定义通知类型,有如下几种:

@Around (优先级最高的通知,可以在目标方法执行之前,之后灵活进行业务拓展.)
@Before (目标方法执行之前调用)
@AfterReturning (目标方法正常结束时执行)
@AfterThrowing (目标方法异常结束时执行)
@After (目标方法结束时执行,正常结束和异常结束它都会执行)

 5.1定义注解代码如下:

package com.cy.pj.common.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredTime{}

5.2定义时间切面对象对象演示通知执行,关键代码如下:

package com.cy.pj.sys.service.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SysTimeAspect {
       
@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredTime)")
   public void doTime(){}

    @Before("doTime()")
    public void doBefore(){
        System.out.println("@Before");
    }

    @After("doTime()")
    public void doAfter(){
        System.out.println("@After");
    }
    @AfterReturning("doTime()")
    public void doAfterReturning(){
        System.out.println("@AfterReturning");
    }

    @AfterThrowing("doTime()")
    public void doAfterThrowing(){
        System.out.println("@AfterThrowing");
    }
    //最重要,优先级也是最高
    @Around("doTime()")
    public Object doAround(ProceedingJoinPoint joinPoint)throws Throwable{
        try {
            System.out.println("@Around.before");
            Object result = joinPoint.proceed();
            System.out.println("@Around.AfterReturning");
            return result;
        }catch(Exception e){
            System.out.println("@Around.AfterThrowing");
            e.printStackTrace();
            throw e;
        }finally {
            System.out.println("@Around.after");
        }
    }
}

5.3切面执行顺序

切面的优先级需要借助@Order注解进行描述,数字越小优先级越高,默认优先级比较低。例如:
定义日志切面并指定优先级。

@Order(1)
@Aspect
@Component
public class SysLogAspect {
 …
}

定义缓存切面并指定优先级: 

@Order(2)
@Aspect
@Component
public class SysCacheAspect {
	…
}

 

切入点增强

切入点的地中方法:

细粒度

@annotation(注解详细路径)

@execution(返回值类型 方法全路径 方法)

粗粒度

@bean("bean(userController)")  @bean("bean(*Controller)") 

@within(包的全路径.*)  @within(包的全路径..*)

package cn.tedu.springweb.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;

@Aspect
@Component
public class LogAspect {
    @Pointcut("@annotation(cn.tedu.springweb.aop.RequiredLog)")
    public void doLong(){};
    //@Around("doLong()")
    //@Around("@annotation(cn.tedu.springweb.aop.RequiredLog)")
    //@Around("bean(userController)")
    //@Around("bean(*Controller)")
    //@Around("within(cn.tedu.springweb..*)")
    //@Around("execution(String cn.tedu.springweb.controller.UserController.aaa())")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Before:"+System.currentTimeMillis());
        Object result = proceedingJoinPoint.proceed();
        System.out.println("After"+System.currentTimeMillis());
        return result;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值