SpringBoot中使用Aspect实现切面,超详细

次元: 365bet提款 时间戳: 2025-09-29 05:10:51 观察者: admin 访问量: 9339 能量值: 482
SpringBoot中使用Aspect实现切面,超详细

Spring中的切面Aspect,这是Spring的一大优势。面向切面编程往往让我们的开发更加低耦合,也大大减少了代码量,同时呢让我们更专注于业务模块的开发,把那些与业务无关的东西提取出去,便于后期的维护和迭代。

相关的学习教程是看的动力节点的视频,然后整理了这篇博客作为笔记,方便以后复习时候看看,也分享给有需要的小伙伴。

视频资源:https://www.bilibili.com/video/BV1XQ4y1m7ex

相关概念

1. 切面(Aspect):

首先要理解‘切’字,需要把对象想象成一个立方体,传统的面向对象变成思维,类定义完成之后(封装)。每次实例化一个对象,对类定义中的成员变量赋值,就相当于对这个立方体进行了一个定义,定义完成之后,就等着被使用,等着被回收。

面向切面编程则是指,对于一个我们已经封装好的类,我们可以在编译期间或在运行期间,对其进行切割,把立方体切开,在原有的方法里面添加(织入)一些新的代码,对原有的方法代码进行一次增强处理。而那些增强部分的代码,就被称之为切面,如下面代码实例中的通用日志处理代码,常见的还有事务处理、权限认证等等。

2. 切入点(PointCut):

要对哪些类中的哪些方法进行增强,进行切割,指的是被增强的方法。即要切哪些东西。

3. 连接点(JoinPoint):

知道了要切哪些方法后,剩下的就是什么时候切,在原方法的哪一个执行阶段加入增加代码,这个就是连接点。如方法调用前,方法调用后,发生异常时等等。

4. 通知(Advice):

通知被织入方法,改如何被增强。定义切面的具体实现。那么这里面就涉及到一个问题,空间(切哪里)和时间(什么时候切,在何时加入增加代码),空间我们已经知道了就是切入点中定义的方法,而什么时候切,则是连接点的概念。

5. 目标对象(Target Object):

被一个或多个切面所通知的对象,即为目标对象。

6. AOP代理对象(AOP Proxy Object):

AOP代理是AOP框架所生成的对象,该对象是目标对象的代理对象。代理对象能够在目标对象的基础上,在相应的连接点上调用通知。

7. 织入(Weaving):

将切面切入到目标方法之中,使目标方法得到增强的过程被称之为织入。

AOP 必须的依赖

org.springframework.boot

spring-boot-starter-aop

日志实体类

package com.space.aspect.bo;

import lombok.Data;

/**

* 系统日志bo

*/

@Data

public class SysLogBO {

private String className;

private String methodName;

private String params;

private Long exeuTime;

private String remark;

private String createDate;

}

日志service

package com.space.aspect.service;

import com.space.aspect.bo.SysLogBO;

import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Service;

@Slf4j

@Service

public class SysLogService {

public boolean save(SysLogBO sysLogBO){

// 这里就不做具体实现了

log.info(sysLogBO.getParams());

return true;

}

}

定义日志注解

package com.space.aspect.anno;

import java.lang.annotation.*;

/**

* 定义系统日志注解

*/

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface SysLog {

String value() default "";

}

声明切面,完成日志记录

以上4点我们的准备工作已经完成。接下来就是重点了

package com.space.aspect.aspect;

import com.google.gson.Gson;

import com.space.aspect.anno.SysLog;

import com.space.aspect.bo.SysLogBO;

import com.space.aspect.service.SysLogService;

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.aspectj.lang.reflect.MethodSignature;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

/**

* 系统日志切面

*/

@Aspect // 使用@Aspect注解声明一个切面

@Component

public class SysLogAspect {

@Autowired

private SysLogService sysLogService;

/**

* 这里我们使用注解的形式

* 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method

* 切点表达式: execution(...)

*

* execution(public * *(..)) 任意的公共方法

* execution(* set*(..)) 以set开头的所有的方法

* execution(* com.LoggerApply.*(..))com.LoggerApply这个类里的所有的方法

* execution(* com.annotation.*.*(..))com.annotation包下的所有的类的所有的方法

* execution(* com.annotation..*.*(..))com.annotation包及子包下所有的类的所有的方法

* execution(* com.annotation..*.*(String,?,Long)) com.annotation包及子包下所有的类的有三个参数,第一个参数为String类型,第二个参数为任意类型,第三个参数为Long类型的方法

* execution(@annotation(com.lingyejun.annotation.Lingyejun))

*/

@Pointcut("@annotation(com.space.aspect.anno.SysLog)")

public void logPointCut() {}

/**

* 环绕通知 @Around , 当然也可以使用 @Before (前置通知) @After (后置通知)

* @param point

* @return

* @throws Throwable

*/

@Around("logPointCut()")

public Object around(ProceedingJoinPoint point) throws Throwable {

long beginTime = System.currentTimeMillis();

Object result = point.proceed();

long time = System.currentTimeMillis() - beginTime;

try {

saveLog(point, time);

} catch (Exception e) {

}

return result;

}

/**

* 保存日志

*/

private void saveLog(ProceedingJoinPoint joinPoint, long time) {

MethodSignature signature = (MethodSignature) joinPoint.getSignature();

Method method = signature.getMethod();

SysLogBO sysLogBO = new SysLogBO();

sysLogBO.setExeuTime(time);

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

sysLogBO.setCreateDate(dateFormat.format(new Date()));

SysLog sysLog = method.getAnnotation(SysLog.class);

if(sysLog != null){

//注解上的描述

sysLogBO.setRemark(sysLog.value());

}

//请求的 类名、方法名

String className = joinPoint.getTarget().getClass().getName();

String methodName = signature.getName();

sysLogBO.setClassName(className);

sysLogBO.setMethodName(methodName);

//请求的参数

Object[] args = joinPoint.getArgs();

try{

List list = new ArrayList();

for (Object o : args) {

list.add(new Gson().toJson(o));

}

sysLogBO.setParams(list.toString());

}catch (Exception e){ }

sysLogService.save(sysLogBO);

}

}

测试

package com.space.aspect.controller;

import com.space.aspect.anno.SysLog;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class TestController {

@SysLog("测试")

@GetMapping("/test")

public String test(@RequestParam("name") String name){

return name;

}

}

这样,我们就成功实现了使用Aspect实现切面记录日志。

相关维度

希尔顿联名卡全方位对比:从小白到大神,总有一款适合你!

希尔顿联名卡全方位对比:从小白到大神,总有一款适合你!

《怪物猎人世界》毒药鸟在哪个区?毒药鸟打法攻略

《怪物猎人世界》毒药鸟在哪个区?毒药鸟打法攻略

汉字:「云」 字形演变 字源演变

汉字:「云」 字形演变 字源演变

中国女篮大胜波多黎各挺进八强

中国女篮大胜波多黎各挺进八强