-
什么是面向切面编程
在传统的面向对象编程中,程序的功能被模块化成各个类和方法,这些类和方法分别处理特定的功能。然而,有些功能可能涉及到多个类、多个方法,例如日志记录、事务管理、性能监控等,这些功能可能在不同的地方重复出现,导致代码的重复性和复杂性增加。
AOP 解决了这个问题,它允许你在程序的运行时,将这些横切逻辑(cross-cutting concerns)从它们所影响的对象中分离出来,然后以一种更模块化的方式进行管理。
-
示例
客户端请求服务端接口时,记录请求的接口信息,包括接口请求时间、接口名称、请求内容以及返回结果等信息。实现步骤如下:
1. 配置log4j的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info"><Loggers><Root level="info"><AppenderRef ref="Console"/><AppenderRef ref="RollingFile"/></Root></Loggers><Appenders><!--控制台输出的配置--><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console><!--输出到文件的配置--><RollingFile name="RollingFile" fileName="./data/logs/app.log"filePattern="./data/logs/app-%d{yyyy-MM-dd}-%i.log.gz"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/><Policies><TimeBasedTriggeringPolicy interval="1" modulate="true"/><SizeBasedTriggeringPolicy size="1 MB"/></Policies><DefaultRolloverStrategy max="10"/></RollingFile></Appenders></Configuration>
2. 在项目中添加依赖(log4j和AOP)
<!-- 引入log4j2依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
<!--AOP--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
3. 创建一个拦截器类,用于拦截Api请求和响应,记录日志。
@Slf4j
@Aspect //定义一个切面
@Component //标记该类作为Spring托管的组件。可以通过依赖注入在其他地方使用
public class ApiMonitorFilter{//在执行com.example.service包下所有的方法之后打印日志@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")public void logAPICall(JoinPoint joinPoint, Object result) {long currentTime = System.currentTimeMillis();String apiName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();ObjectMapper objectMapper = new ObjectMapper();String aa=null;try {aa=objectMapper.writeValueAsString(args);} catch (JsonProcessingException e) {throw new RuntimeException(e);}log.info("进入过滤器:开始监控api信息.........");log.info("接口相应时间{}:",currentTime);log.info("接口名称{}:",apiName);log.info("请求内容{}:",aa);log.info("响应结果{}:",result);}
}
2. 写一个接口
//@Controller //@Controller返回的是一个视图View,需要搭配@ResponseBody使用,两个的结合相当于@RestController,可以直接返回一个对象。
//@ResponseBody
@RestController
@RequestMapping("/api/test")
@Slf4j
public class TestController {@ResourceTestService testService; //接口中调用的方法 import com.example.service.TestService;@PostMapping(value = "/getValue")public String GetValue(int a,int b){log.info("进入Controller");String result=testService.CalculateValue(a,b);return result;}
}
运行结果: