做微信平台网站,个人网站如果做,实现网站计划书,招投标网站开发AOP基础
概述 AOP#xff1a;Aspect Oriented Programming#xff08;面向切面编程、面向方面编程#xff09;#xff0c;面向特定方法的编程。 动态代理是面向切面编程最主流的实现。 SpringAOP是Spring框架的高级技术#xff0c;旨在管理bean对象的过程中#xff0c…AOP基础
概述 AOPAspect Oriented Programming面向切面编程、面向方面编程面向特定方法的编程。 动态代理是面向切面编程最主流的实现。 SpringAOP是Spring框架的高级技术旨在管理bean对象的过程中主要通过底层的动态代理机制对特定的方法进行编程。
入门程序 需求 统计各个业务层方法的执行耗时 步骤 导入依赖 !-- AOP依赖--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency 编写代码 package com.testpeople.aop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;Component
Slf4j
Aspect //AOP类
public class TimeAspect {Around(execution(* com.testpeople.service.*.*(..))) //切入点表达式public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {//1.记录开始时间long begin System.currentTimeMillis();//2.调用原始方法运行Object result joinPoint.proceed();//3.记录结束时间long end System.currentTimeMillis();//日志log.info(joinPoint.getSignature()方法执行耗时{}ms,end-begin);return result;}} 效果 优势 场景 记录日志 权限控制 事务管理 优势 代码无侵入 减少重复代码 提高开发效率 维护方便
核心概念 连接点 JoinPoint,可以被AOP控制的方法暗含方法执行时的相关信息 通知 Advice,指哪些重复的逻辑也就是共性功能体现为一个方法 切入点 PointCut,匹配连接点的条件通知仅会在切入点方法执行时被应用 切面 Aspect,描述通知与切入点的对应关系通知切入点 目标对象 Target,通知所应用的对象
图解 流程 进行开发后使用的是代理对象而不是实际对象。
AOP进阶
通知类型 Around环绕通知此注解标注的通知在目标方法前后都被执行。 Before: 前置通知此注解标注的通知方法在目标方法前被执行。 After: 后置通知此注解标注的通知方法在目标方法被执行无论是否异常都会执行。 AfterReturning: 返回后通知此注解标注的通知方法在目标方法后被执行有异常不执行。 AfterThrowing: 异常后通知此注解标注的通知方法发生异常后执行。
测试
package com.testpeople.aop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;Component
Slf4j
Aspect
public class MyAspect {Before(execution(* com.testpeople.service.impl.DeptServiceImpl.*(..)))public void before(){log.info(前置通知);}Around(execution(* com.testpeople.service.impl.DeptServiceImpl.*(..)))public Object around(ProceedingJoinPoint joinPoint) throws Throwable {log.info(环绕通知before);Object result joinPoint.proceed();log.info(环绕通知after);return result;}After(execution(* com.testpeople.service.impl.DeptServiceImpl.*(..)))public void after(){log.info(后置通知);}AfterReturning(execution(* com.testpeople.service.impl.DeptServiceImpl.*(..)))public void afterReturning(){log.info(后置返回通知);}AfterThrowing(execution(* com.testpeople.service.impl.DeptServiceImpl.*(..)))public void afterThrowing(){log.info(后置异常通知);}}
效果 注意 Around环绕通知需要自己调用 ProceedingJoinPoint.proceed(); Around环绕通知方法的返回值必须指定为Object,来接受原始方法的返回值。
tips 切入点表达式抽取
package com.testpeople.aop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;Component
Slf4j
Aspect
public class MyAspect {Pointcut(execution(* com.testpeople.service.impl.DeptServiceImpl.*(..)))private void pt(){}//这个方法可以改修订范围然后被别的包引用。Before(pt())public void before(){log.info(前置通知);}Around(pt())public Object around(ProceedingJoinPoint joinPoint) throws Throwable {log.info(环绕通知before);Object result joinPoint.proceed();log.info(环绕通知after);return result;}After(pt())public void after(){log.info(后置通知);}AfterReturning(pt())public void afterReturning(){log.info(后置返回通知);}AfterThrowing(pt())public void afterThrowing(){log.info(后置异常通知);}}
通知顺序 不同切面类中默认按照切面类的类名字母排序 目标方法前的通知方法字母排名靠前的先执行。 目标方法后的通知方法字母排名靠前的后执行。 用Order(数字)加在切面类上来控制顺序 目标方法前的通知方法数字小的先执行 目标方法后的通知方法数字小的后执行 概述 描述切入点方法的一种表达式 作用 主要用来决定项目中的哪些方法需要加入通知 常见形式 execution(...)根据方法的签名来匹配 特殊符号 如果匹配两个方法可以使用“||”连接。 Tips annotation(...)根据注解匹配 新建注解 package com.testpeople.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 MyLog {} 在需要添加方法上添加注解更换切入点表达式。 Around(annotation(com.testpeople.aop.MyLog))
连接点 开发 Around(annotation(com.testpeople.aop.MyLog))
public Object testJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {//1.获取 目标对象的类名String className joinPoint.getTarget().getClass().getName();log.info(className);//2.获取 目标方法的方法名String methodName joinPoint.getSignature().getName();log.info(methodName);//3.获取 目标方法运行时传入的参数Object[] methodArgs joinPoint.getArgs();log.info(Arrays.toString(methodArgs));//4.放行 目标方法执行Object result joinPoint.proceed();//5.获取 目标方法的返回值log.info(result.toString());return result;//此处可以改变函数的返回结果(添加其他方法)
}
效果 AOP案例(操作日志记录功能)
需求 将案例中 增、删、改相关的接口的操作日志记录到数据库表中 日志信息~操作人、操作时间、执行方法的全类名、执行方法、方法运行时的参数、返回值、方法执行的时长。
思路 步骤 准备 在案例中引入AOP的依赖 !-- AOP依赖--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency 设计好数据库表 # 操作日志记录表
create table operate_log(id int unique primary key auto_increment comment ID,operate_user int unsigned comment 操作人ID,operate_time datetime comment 操作时间,class_name varchar(100) comment 操作类名,method_name varchar(100) comment 操作方法名,method_params varchar(1000) comment 操作方法参数,return_value varchar(2000) comment 返回值,cost_time bigint comment 耗时,单位:ms
) comment 操作日志记录表; 设计好实体类 package com.testpeople.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;Data
AllArgsConstructor
NoArgsConstructor
public class OperateLog {private Integer id;//IDprivate Integer operateUser;//操作人IDprivate LocalDateTime operateTime;//操作时间private String className;//操作类名private String methodName;//方法名private String methodParams;//方法参数private String returnValue;//返回值private Long costTime;//耗时} Mapper接口 package com.testpeople.mapper;import com.testpeople.pojo.OperateLog;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;Mapper
public interface OperateLogMapper {//插日志数据Insert(insert into operate_log (operate_user,operate_time,class_name,method_name,method_params,return_value,cost_time) values(#{operateUser},#{operateTime},#{className},#{methodName},#{methodParams},#{returnValue},#{costTime}))void insert(OperateLog operateLog);} 编码 自定义注解 package com.testpeople.anno;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 Log {
} 定义切面类完成记录操作日志的逻辑 package com.testpeople.aop;import com.alibaba.fastjson.JSONObject;
import com.testpeople.mapper.OperateLogMapper;
import com.testpeople.pojo.OperateLog;
import com.testpeople.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;Slf4j
Component
Aspect
public class LogAspct {Autowiredprivate HttpServletRequest request;Autowiredprivate OperateLogMapper operateLogMapper;Around(annotation(com.testpeople.anno.Log))public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {//操作人ID~ 当前员工ID//获取请求头中的jwt令牌中的员工IDString jwt request.getHeader(token);//解析Integer operateUser (Integer) JwtUtils.parseJwt(jwt).get(id);//操作时间LocalDateTime operateTime LocalDateTime.now();//类名String className joinPoint.getTarget().getClass().getName();//方法名String methodName joinPoint.getSignature().getName();//方法参数Object[] args joinPoint.getArgs();String methodParams Arrays.toString(args);//记录时间long begin System.currentTimeMillis();//调用原始目标方法运行Object result joinPoint.proceed();//记录结束时间long end System.currentTimeMillis();//方法返回值String returnValue JSONObject.toJSONString(result);//耗时long costTime end - begin;//记录操作日志OperateLog operateLog new OperateLog();operateLog.setOperateUser(operateUser);operateLog.setOperateTime(operateTime);operateLog.setClassName(className);operateLog.setMethodName(methodName);operateLog.setMethodParams(methodParams);operateLog.setReturnValue(returnValue);operateLog.setCostTime(costTime);operateLogMapper.insert(operateLog);log.info(AOP记录操作日志 {},operateLog.toString()\n);return result;}} 给有需求的类添加Log注解
效果 注意 获取当前用户 从request中获取token 在token中提取当前用户id 以上是对SpringBoot框架中的AOP相关的介绍以及简单的使用通过一个操作记录日志功能进行练习。多点关注、多点爱。以上知识点笔记来自于小编学习黑马程序员的课程所记录
项目地址
admin_web_project: 黑马程序员项目javaWebjavaWeb开发学习仓库前后端分离项目前端Vue后端springboot数据库Mysql