【Spring学习】AOP实现⽇志记录
AOP知识点
AOP,⾯向切⾯编程。通过预编译⽅式和运⾏时动态代理实现在不修改源代码的情况下给程序动态统⼀添加功能的⼀种技术。
AOP编程思想就是把很多类对象中的横切问题点,从业务逻辑中分离出来,减少代码的冗余和降低模块间的耦合度,提⾼开发效率。
简单说就是:把程序⾥重复的代码抽取出来,在需要执⾏的时候,使⽤动态代理的技术,在不修改源码的基础上,对已有⽅法进⾏增强。常⽤于⽇志记录、事务处理、权限验证等等。
AOP的核⼼原理
Spring AOP就是基于动态代理的,通过JDK动态代理或CGLib代理在运⾏时期在对象初始化阶段织⼊代码的。如果要代理的对象,实现了某个接⼝,那么AOP会使⽤JDK Proxy,去创建代理对象,⽽对于没有实现接⼝的对象, AOP会使⽤CGLib⽣成⼀个被代理对象的⼦类来作为代理。
AOP中主要概念理解
aspect:切⾯,切⾯由切点和通知组成,即包括横切逻辑的定义也包括连接点的定义;
pointcut:切点,每个类都拥有多个连接点,可以理解是连接点的集合;
joinpoint:连接点,程序执⾏的某个特定位置,如某个⽅法调⽤前后等;
weaving:织⼊,将增强添加到⽬标类的具体连接点的过程;
advice:通知,织⼊到⽬标类连接点上的⼀段代码,就是增强到什么地⽅?增强什么内容?
target:⽬标对象,通知织⼊的⽬标类;
aop Proxy:代理对象,即增强后产⽣的对象。
AOP五种通知⼯作
前置通知:在⽬标⽅法调⽤之前执⾏,可以获得切⼊点信息;
后置通知:在⽬标⽅法执⾏后执⾏,⽬标⽅法有异常不执⾏;
异常通知:在⽬标⽅法抛出异常时执⾏,可以获取异常信息;
最终通知:在⽬标⽅法执⾏后执⾏,⽆论是否有异常都执⾏;
环绕通知:最强⼤的通知类型,在⽬标⽅法执⾏前后操作,可以阻⽌⽬标⽅法执⾏。
实现AOP的三种⽅式
通过Spring API实现;
⾃定义类来实现AOP;
使⽤注解实现(常⽤)。
Spring⾥执⾏步骤
1、定义⼀个切⾯类Aspect
spring aop应用场景声明⼀个切⾯类,增加@Component和@Aspect两个注解,同时SpringBoot要引⼊spring-boot-stater-aop依赖包。
2、定义切点Pointcut
定义切点,并定义切点在哪些地⽅执⾏,采⽤@Pointcut注解完成,如@Pointcut(public * *.*(...))
规则:修饰符(可以不写)+返回类型+包下的类+⽅法+⽅法参数 “*”代表不限,“..”两个点代表参数不限,例如:
切点名称myPointcut,在返回类型不限的com.binlog.ller包下的所有类,所有⽅法并且参数不限。
参考:@Pointcut(value="execution(* com.binlog.ller.*.*(..))")
3、定义Advice通知
利⽤通知的5种类型注解@Before、@After、@AfterReturning、@AfterThrowing、@Around来完成在某些切点的增强动作。
使⽤Spring实现AOP
1、创建⼀个新的springboot⼯程,然后添加依赖包:
<!--AOP依赖包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
2、分别创建两个包,⼀个是aspect和controller。
3、controller包⾥创建⼀个普通访问类AopUserController,代码如下:
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api/aop")
public class AopUserController {
@GetMapping("/getUserByName")
public String name(@RequestParam("name") String name) {
return "Hello:" + name;
}
@GetMapping("/getUserList")
public List<String> getUser() {
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
return list;
}
}
4、aspect包⾥创建⽇志切⾯类AopLog,代码如下:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.t.request.RequestContextHolder;
import org.t.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class AopLog {
private Logger logger = Class());
ThreadLocal<Long> startTime = new ThreadLocal<>();
//定义切点
@Pointcut(value = "execution(* com.binlog.ller.*.*(..))")
public void aopWebLog() {
}
/
/使⽤环绕通知
@Around("aopWebLog()")
public Object myLogger(ProceedingJoinPoint pjp) throws Throwable {
startTime.set(System.currentTimeMillis());
//使⽤ServletRequestAttributes请求上下⽂获取⽅法更多
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestAttributes();        HttpServletRequest request = Request();
String className = Signature().getDeclaringTypeName();
String methodName = Signature().getName();
//使⽤数组来获取参数
Object[] array = Args();
ObjectMapper mapper = new ObjectMapper();
//执⾏函数前打印⽇志
logger.info("调⽤前:{}:{},传递的参数为:{}", className, methodName, mapper.writeValueAsString(array));        logger.info("URL:{}", RequestURL().toString());
logger.info("IP地址:{}", RemoteAddr());
//调⽤整个⽬标函数执⾏
Object obj = pjp.proceed();
//执⾏函数后打印⽇志
logger.info("调⽤后:{}:{},返回值为:{}", className, methodName, mapper.writeValueAsString(obj));
logger.info("耗时:{}ms", System.currentTimeMillis() - ());
return obj;
}
}
5、项⽬启动后,浏览器页⾯访问:
控制台输出结果:
控制台输出结果:
⾄此⼀个简单的⽇志记录就完成了。平时开发⾥还需根据业务进⾏优化或补充!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。