springboot aop 详细配置示例,注解配置aop

本文详细介绍了AOP(面向切面编程)的概念,SpringBoot中的AOP应用,包括通知的类型、SpringbootAOP的依赖配置,以及在Spring5和4版本中通知的执行顺序。通过实例展示了如何在SpringBoot项目中使用AOP进行功能切分和增强。
摘要由CSDN通过智能技术生成

AOP 简介

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP的优势

  1. 提高代码的可重用性
  2. 业务代码编码更简洁
  3. 业务代码维护性更高效
  4. 业务功能扩展更便捷

AOP的相关概念

  1. Joinpoint(连接点):就是方法,可以说每个controller里面的方法都可以称作连接点。
  2. Pointcut(切入点):就是挖掉共性功能的方法,可以说连接点(方法)有的被挖出了一些功能,这些被抽出共性代码的连接点叫切入点。
  3. Advice(通知):就是切入点被挖出的共性功能代码,组成了一个方法称为通知
  4. Aspect(切面):就是共性功能(通知)与挖的位置的对应关系,因为该共性功能可以在,切入点前面(前置通知),切入点后面(后置通知),切入点周围(环绕通知),切入点抛异常时执行(抛异常通知),切入点返回后执行(返回后通知),可以理解为切入点方法和通知方法配置时放在了一个类中来描述两者的关系,该类具有切面的功能。
  5. Target(目标对象):就是挖掉功能的方法对应的类产生的对象,这种对象无法直接完成最终功能,例如一个controller里面有方法被挖去了共性功能组成了一个通知,此时必须两者一起才能完成总功能。
  6. Weaving(织入):就是将挖掉的功能回填到对应的方法的动态过程。
  7. Proxy(代理):目标对象无法直接完成工作,需要对其进行功能回填,通过创建原始对象的代理对象来实现。
  8. Introduction(引入/引介):就是对原始对象无中生有的添加成员变量的成员方法,原始对象被织入被挖去的功能叫织入,也可以添加原来不存在的方法,属性,此时叫引入或介入。

通知的类型

1.	前置通知	       方法前
2.	后置通知	       方法后,发生异常不执行	
3.	环绕通知	       方法前后
4.	返回后通知	   方法后,如果发生异常不会执行
5.	抛出异常后通知	只有发生异常后会通知 

springboot aop 依赖 配置

```xml
<!-- SpringBoot测试 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

<!-- 开启web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

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

springboot AOP举例

package com.wulaizhi.aop.aop;

import com.wulaizhi.aop.annotation.MyAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AspectTest {
        /**
         * 切入点表达式
         */
        @Pointcut("execution(* com.wulaizhi.aop.service.*Service.*(..))")
        public void pointCut() {
        }

        /**
         * 前置通知
         */
        @Before("pointCut()")
        public void before() {
                System.out.println("前置通知");
        }

        /**
         * 后置通知
         */
        @After("pointCut()")
        public void after() {
                System.out.println("后置通知");
        }

        /**
         * 环绕通知
         */
        @Around("pointCut()")
        public Object around2(ProceedingJoinPoint joinPoint) throws Throwable {
//                获取参数

//                介绍ProceedingJoinPoint:
//
//                getArgs:可以获取方法的参数
//
//                getTarget: 可以获取目标对象,通过反射可以获取其他信息

                Object[] args = joinPoint.getArgs();
                System.out.println(args);
                Object target = joinPoint.getTarget();
                System.out.println(target.getClass().getName());

                System.out.println("环绕通知前置");
                Object result = joinPoint.proceed();
                System.out.println("环绕通知后置");
                return result;
        }




        /**
         * 异常通知
         */
        @AfterThrowing(value = "pointCut()", throwing = "t")
        public void afterThrowing(Throwable t) {
                System.out.println("异常通知" + t.getMessage());
        }

        /**
         * 注解环绕通知
         */
        //注解该注解里面的值为下面函数参数的形参
        @Around("@annotation(myAnnotation)")
        public Object around3(ProceedingJoinPoint joinPoint,MyAnnotation myAnnotation) throws Throwable {
                System.out.println("注解环绕通知前置+注解值:"+myAnnotation.role());
                Object result = joinPoint.proceed();
                System.out.println("注解环绕通知后置+注解值:"+myAnnotation.role());
                return result;
        }
}

@MyAnnotation

package com.wulaizhi.aop.annotation;

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

//限定该注解只能是方法上可用
@Target(ElementType.METHOD)
//此自定义注解可以存活到字节码文件阶段
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String role() default "";
}


UserService

package com.wulaizhi.aop.service;

import com.wulaizhi.aop.domain.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;
public interface UserService extends IService<User>  {
        void add();

        void delete();

        void updateUser();

        User queryById(Integer id);


}

UserMapper

package com.wulaizhi.aop.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wulaizhi.aop.domain.entity.User;
import org.springframework.stereotype.Component;

@Component
public interface UserMapper extends BaseMapper<User> {

}

UserServiceImpl

package com.wulaizhi.aop.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wulaizhi.aop.annotation.MyAnnotation;
import com.wulaizhi.aop.domain.entity.User;
import com.wulaizhi.aop.mapper.UserMapper;
import com.wulaizhi.aop.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User>implements UserService {

    @Override
    @MyAnnotation(role="admin")
    public void add() {
//            抛出异常
//        int i = 1 /0;
        System.out.println("add方法调用");
    }

    @Override
    public void delete() {
        System.out.println("delete方法调用");
    }

    @Override
    public void updateUser() {
        System.out.println("update方法调用");
    }

    @Override
    public User queryById(Integer id) {
        System.out.println("query方法调用");
        return null;
    }
}

Springboot AOP 通知的执行顺序

  1. 同一个切面类有相同类型的通知,依靠通知方法的名称来排序,此时通知的方法名称要例如:around1,around2,假如这是两个环绕通知作用与同一切入点,则执行顺序和通知名称中的1,2,数字有关
  2. 不同切面类的执行顺序可以用@Order()注解来配置。
  3. 同一切面类不同的通知的执行顺序如下图,

spring 5,对应无异常和有异常的执行顺序。

请添加图片
在这里插入图片描述

spring 4 对应无异常和有异常的执行顺序。

请添加图片描述

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值