-
什么是面向切面编程
在传统的面向对象编程中,程序的功能被模块化成各个类和方法,这些类和方法分别处理特定的功能。然而,有些功能可能涉及到多个类、多个方法,例如日志记录、事务管理、性能监控等,这些功能可能在不同的地方重复出现,导致代码的重复性和复杂性增加。
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 {
@Resource
TestService 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;
}
}
运行结果: