Spring AOP 注解及使用示例

什么是 AOP

AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。

切面:相当于应用对象间的横切点,我们可以将其单独抽象为单独的模块

 

 

AOP 术语

AOP 领域中的特性术语:

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
  • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的结合。
  • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入

 

通过注解声明切点指示器

 

AspectJ指示器描述
arg() 限制连接点匹配参数为指定类型的执行方法
@args() 限制连接点匹配参数由指定注解标注的执行方法
execution() 用于匹配是连接点的执行方法
this() 限制连接点匹配AOP 代理的Bean 引用为指定类型的类
target() 限制连接点匹配目标对象为指定类型的类
@target() 限制连接点匹配特定的执行对象.这些对象对应的类要具备指定类型的注解
within() 限制连接点匹配指定的类型
@within() 限制连接点匹配指定注解所标注的类型(当使用Spring AOP时,方法定义在由指定的注解所标注的类里)
@annotation() 限制匹配带有指定注解连接点

 

通过注解声明 5 种通知类型

注解描述
@Before 通知方法会在目标方法调用之前执行
@After 通知方法会在目标方法返回或异常后调用
@AfterReturning 通知方法会在目标方法返回后调用
@AfterThrowing 通知方法会在目标方法抛出异常后调用
@Around 通知方法会将目标方法封装起来
@Pointcut   //定义切点位置

使用:
@Pointcut("execution(* com.springinaction.springidol.Instrument.play(..))")

 

 

 

 

 

 

 

AOP 示例

下列代码基于SpringBoot 工程,部分代码已省略,请自行创建

1.创建AopController.java

复制代码
package com.soft.controller;

import com.google.gson.Gson;
import com.soft.service.IAopService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 *  Aop测试
 * @description: AopController
 * @author: suphowe
 * @create: 2019-12-25 14:46
 **/
@RestController
@RequestMapping("/aop")
@Api(value = "Aop切面编程测试")
public class AopController {

    @Autowired
    private IAopService aopService;

    @ResponseBody
    @RequestMapping(value = "/method_one", method = RequestMethod.POST)
    @ApiOperation(value = "方法1", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "msg", value = "msg", required = false, dataType = "String")
    })
    public String method_one(String msg){
        String result = aopService.method_one(msg);
        return result;
    }
}
复制代码

 

2.创建 IAopService.java 和 AopServiceImpl.java

package com.soft.service;

public interface IAopService {

    String method_one(String msg);
}

 

复制代码
package com.soft.service.impl;

import com.soft.service.IAopService;
import org.springframework.stereotype.Service;


@Service
public class AopServiceImpl implements IAopService {

@Override
public String method_one(String msg){
System.out.println("==>接收信息:" + msg);
return "return method_one";
}
}
复制代码

 

3.创建 SysAspect.java

复制代码
package com.soft.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SysAspect {

/**
* 声明切点
*/
@Pointcut("execution(* com.soft.service.*.*(..))")
public void point(){}

/**
* 通知方法会在目标方法调用之前执行
*/
@Before("point())")
public void before() {
System.out.println("before ==> 通知方法会在目标方法调用之前执行");
}

/**
* 通知方法会在目标方法返回或异常后调用
*/
@After("point()")
public void after() {
System.out.println("After ==> 通知方法会在目标方法返回或异常后调用");
}

/**
* 通知方法会在目标方法返回后调用
*/
@AfterReturning("point()")
public void afterReturing() {
System.out.println("AfterReturning ==> 通知方法会在目标方法返回后调用");
}

/**
* 通知方法会在目标方法抛出异常后调用
*/
@AfterThrowing("point()")
public void afterThrowing() {
System.out.println("AfterThrowing ==> 通知方法会在目标方法抛出异常后调用");
}

/**
* 通知方法会将目标方法封装起来
* @param proceeding
*/
@Around("point()")
public Object around(ProceedingJoinPoint proceeding) throws Exception{
//和JoinPoint一样,ProceedingJoinPoint也可以获取
//连接点方法的实参
Object[] args=proceeding.getArgs();
//连接点方法的方法名
String methodName=proceeding.getSignature().getName();
//连接点方法所在的对象
Object targetObj=proceeding.getTarget();
String targetClassName=targetObj.getClass().getName();

Object result=null;
try {
System.out.println("前置通知==>参数:" + args[0]);
System.out.println("前置通知==>执行方法:" + methodName);
//执行连接点的方法 获取返回值
result=proceeding.proceed(args);
System.out.println("返回通知==>返回结果:" + result);
}catch (Throwable e) {
System.out.println("异常通知==>" + e);
}finally {
System.out.println("最终通知==>执行结束");
}
return result;
}

}
复制代码

 

4.启动工程,通过Swagger-ui.html访问

 

swagger访问结果

 

 

 

 

 

控制台日志输出结果

posted @   suphowe  阅读(968)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示

目录导航