AOP使用示例:日志采集功能

AOP使用示例:日志采集功能

背景: 目的是为了优化CalledListRequest接口,深入了解后发现这个接口写的不是那么好,循环调用某个接口。导致某些简单的查询被反复执行。从而效率。然后这个接口涉及到的业务逻辑太过于复杂,没敢直接改。而是新写了个接口取代它。但是为了做更充分的测试。先线上采集请求参数。然后进行测试。最后在发布上线是最好的方式。

功能以及原理介绍

为了收集线上这个接口(CalledListRequest)的请求参数。

原理:写一个方法,将传递过来的参数全部插入到数据库的日志表里面。
但是为了减少侵入性(就是不改变原有接口的实现代码)。我这里使用了AOP切入的方式。同时配合apollo做了一个开关(控制什么时候开始收集,什么时候关闭收集)

主要的一个技能点就是对AOP的应用了,之前其实没有实际工作去应用到AOP,这一次算是个机会了

其实特别简单,直接的核心代码就好了。没有复杂的东西

核心代码

package com.centanet.bizcom.config.log;

import com.alibaba.fastjson.JSON;
import com.centanet.bizcom.config.apollo.ApolloConfig;
import com.centanet.bizcom.config.ddb.MultiTenantChanger;
import com.centanet.bizcom.mapper.BizMapper;
import com.centanet.bizcom.model.entity.LogCollection;
import com.centanet.bizcom.util.CityHelper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * 该类的功能是为了收集日志
 * 方便切换接口时使用
 * @Author: wbdengtt
 * @Date: 2020/10/13 14:58
 */
 //声明切面
@Aspect
// 交给Spring管理bean
@Component
public class LogCollectAspect {
	// 注入logCollection 这个就是一个简单实体entity。
    @Autowired
    private LogCollection logCollection;
    // 这是将实体存到数据库的mapper
    @Autowired
    private BizMapper bizMapper;
    // 拦截CalledController.calledListRequest方法。通过这个配置。可以拦截更多东西,这个规则相信的可以看下面的参考文章
    @Pointcut("execution(* com.centanet.bizcom.controller.CalledController.calledListRequest(..))")
    public void myPointCut() {
        // 这个其实就是一个切点,不需要方法内容
    }
    // 这个是具体实现拦截参数,并将参数日志写入到数据库的方法
    @Before("myPointCut()")
    public void logCollect(JoinPoint joinPoint) {
    	// 这个是在apoll配置的开关(就是一个String变量)。如果开了才进行下面的拦截。
        boolean isLogCollect = "true".equalsIgnoreCase(ApolloConfig.getWebValue(CityHelper.getCityCode(),"isLogCollectionOpen"))
                && ApolloConfig.getWebValue(CityHelper.getCityCode(),"logCollectCity").contains(CityHelper.getCityen());
        if (isLogCollect) {
        	// 设置logCollection的日期字段
            logCollection.setRowDate(new Date());
            // 获取当前HttpServletRequest 对象 这个是为了拿到各种我需要的信息。关于HttpServletRequest 下面有提供参考链接看相信的介绍
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
			//设置logCollection的实体字段,这里是请求类型.城市
			logCollection.setMethodName(request.getMethod()+"."+CityHelper.getCityen());
            //request.getQueryString() 只能拿到get请求的参数。如果是post请求,得通过joinPoint才能拿到参数(这个不需要手动声明,应该是SpringAOP哪里给自动注入了) 
            logCollection.setMessage(JSON.toJSONString(joinPoint.getArgs()));
            if (logCollection.getMessage() ==null){
                logCollection.setMessage("没能拿到参数");
            }
            // request.getRequestURI()获取方法名
            logCollection.setFullName(request.getRequestURI());
            // 写入数据库  MultiTenantChanger是因为我有多个数据库,但是这里的操作其实就是讲实体装入数据库
            MultiTenantChanger.setDataSourceType(CityHelper.getCityCode()+MultiTenantChanger.CENTA_BIZ);
            bizMapper.insertLogCollection(logCollection);
            MultiTenantChanger.removeRouteKey();
        }
    }
}

我给代码加了许多注释。应该是比较好明白的

参考文章:
Joinpoint:
https://blog.csdn.net/qq_15037231/article/details/80624064
HttpServletRequest相关:
https://blog.csdn.net/cold___play/article/details/100920952
execution规则:
https://blog.csdn.net/weixin_39209728/article/details/83752754
AOP简介(这篇是我自己以前写的)
https://blog.csdn.net/m0_37628958/article/details/106201011

<think>嗯,用户之前已经问过关于购物网站推荐系统的设计和实现,现在他们又进一步询问具体实现,特别是想用AOP(面向切面编程)。我需要先回顾一下之前的对话,确保这次的回答在之前的基础上更深入,并且结合AOP的应用。 用户可能对AOP不太熟悉,或者希望了解如何将AOP应用到推荐系统的某些模块中。之前给出的方案涵盖了数据采集、处理、模型预测、推送和数据存储,现在需要在这些模块中找到适合AOP的场景。 首先,AOP通常用于处理横切关注点,比如日志记录、性能监控、事务管理、权限检查等。在推荐系统中,可能的切面包括日志记录、性能统计、异常处理、重试机制、数据校验等。需要确定在哪些步骤中引入AOP可以简化代码,提高可维护性。 接下来,用户可能希望具体的实现方案,所以需要提供代码示例,特别是使用Python中的AOP库,比如aspectlib或者装饰器。需要注意的是,Python的AOP支持不如Java的Spring AOP或AspectJ强大,可能需要使用装饰器或中间件的方式来实现。 需要分析之前的模块,比如用户行为采集、数据处理、模型预测、推送和数据存储,找出其中可以应用AOP的地方。例如,在数据采集的API接口处,使用AOP记录日志;在模型预测时,使用AOP进行性能监控;在数据存储时,使用AOP处理异常和重试。 同时,用户可能关心如何将AOP与现有系统集成,是否需要额外的框架或库,以及实现的复杂度。需要解释在Python中如何实现AOP,可能的方法和工具,并给出具体的代码示例,如使用装饰器或中间件拦截方法调用。 另外,用户可能希望了解使用AOP带来的好处,比如代码解耦、复用性提高、维护方便等,以及潜在的注意事项,如性能影响、调试难度增加等。需要平衡这些点,给出实际应用的建议。 最后,确保回答结构清晰,分步骤说明如何将AOP应用到推荐系统的各个模块,并提供具体的实现代码和优化建议。同时,提醒用户在实际应用中需要考虑的监控和测试方面,比如日志切面的性能影响,是否需要异步处理等。</think>以下是结合AOP(面向切面编程)的具体实现方案,重点优化日志、性能监控和数据校验等横切关注点: --- ### **一、AOP应用场景设计** ![](https://via.placeholder.com/500x200.png?text=AOP在推荐系统的切面设计) **核心切面**: 1. **行为日志切面**:自动记录接口调用日志 2. **性能监控切面**:统计模型预测耗时 3. **异常重试切面**:MySQL写入失败自动重试 4. **数据校验切面**:拦截非法用户ID/商品ID --- ### **二、具体实现代码(Python示例)** #### **1. AOP基础框架搭建** 使用`aspectlib`库实现切面编程: ```python from aspectlib import Aspect, weave # 定义日志切面 class LogAspect(Aspect): def around(self, *args, **kwargs): print(f"[AOP-LOG] 调用方法: {self.__name__}, 参数: {args}") result = yield # 执行原方法 print(f"[AOP-LOG] 返回结果: {result}") return result # 定义性能监控切面 class PerfAspect(Aspect): def around(self, *args, **kwargs): start = time.time() result = yield cost = time.time() - start print(f"[AOP-PERF] 方法 {self.__name__} 耗时: {cost:.2f}s") return result ``` --- #### **2. 关键模块与AOP集成** ##### **(1) 用户行为采集接口** ```python # 将切面织入API接口 @weave(UserBehaviorAPI, methods=['POST']) class UserBehaviorAspect(LogAspect, PerfAspect): pass # 原始接口代码示例 class UserBehaviorAPI: def post(self, data): # 写入Kafka kafka_producer.send('user_behavior', data) ``` ##### **(2) 推荐模型预测** ```python # 模型预测+异常重试切面 class RetryAspect(Aspect): def around(self, *args, **kwargs): retries = 3 for i in range(retries): try: result = yield return result except Exception as e: print(f"[AOP-RETRY] 第{i+1}次重试,异常: {str(e)}") @weave(RecommendModel.predict, RetryAspect) class ModelPredictAspect(LogAspect, PerfAspect): pass ``` ##### **(3) 数据存储切面** ```python # MySQL写入校验切面 class DataValidateAspect(Aspect): def before(self, *args, **kwargs): if not validate_user_id(args[1]['user_id']): raise ValueError("非法用户ID") @weave(MySQLClient.insert, DataValidateAspect) class MySQLAspect(LogAspect): pass ``` --- ### **三、AOP配置优化** #### **1. 切面优先级配置** ```yaml # aspect_config.yaml aspects: - name: data_validate pointcut: "MySQLClient.*" order: 1 # 最高优先级 - name: perf_monitor pointcut: "RecommendModel.*" order: 2 ``` #### **2. 动态切面开关(生产环境)** ```python # 通过环境变量控制切面 if os.getenv("ENABLE_AOP_LOG") == "true": weave_all(LogAspect) ``` --- ### **四、典型AOP应用场景** #### *
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值