Привет всем, в этой главе мы добавляем функцию асинхронного ведения журнала aop. Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь со мной по адресу mr_beany@163.com. Также попросите руководства великих богов, спасибо
Первый: добавить зависимости АОП
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Второе: создание пользовательских аннотаций и аспектов
Создать папку core→aop
Создайте заметку в папке aop, где заметка — это записанная заметка.
package com.example.demo.core.aop;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AnnotationLog {
String remark() default "";
}
Создать фрагмент
Примечание: оSystemLog
класс, передВ этой статье интегрируется генератор для автоматического создания функций модели, xml и dao.Я упоминал об этом, если вы забудете, вы можете прочитать это снова
package com.example.demo.core.aop;
import com.alibaba.fastjson.JSON;
import com.example.demo.core.systemlog.SystemLogQueue;
import com.example.demo.core.ret.ServiceException;
import com.example.demo.core.utils.ApplicationUtils;
import com.example.demo.model.SystemLog;
import com.example.demo.model.UserInfo;
import com.example.demo.service.SystemLogService;
import org.apache.ibatis.javassist.*;
import org.apache.ibatis.javassist.bytecode.CodeAttribute;
import org.apache.ibatis.javassist.bytecode.LocalVariableAttribute;
import org.apache.ibatis.javassist.bytecode.MethodInfo;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: aop记录操作日志
* @author 张瑶
* @date 2018年5月28日 18:43:28
*/
@Aspect
@Component
public class AspectLog {
private static final Logger logger = LoggerFactory.getLogger(AspectLog.class);
@Resource
private SystemLogService systemLogService;
/**
* 定义切点
*/
@Pointcut("@annotation(com.example.demo.core.aop.AnnotationLog)")
public void methodCachePointcut() {
}
@Before("methodCachePointcut()")
public void doBefore(JoinPoint p) throws Exception{
SystemLog systemLog = getSystemLogInit(p);
systemLog.setLogType(SystemLog.LOGINFO);
systemLogService.insert(systemLog);
}
/**
* 调用后的异常处理
* @param p
* @param e
*/
@AfterThrowing(pointcut = "methodCachePointcut()", throwing = "e")
public void doAfterThrowing(JoinPoint p, Throwable e) throws Throwable {
//业务异常不用记录
if(!(e instanceof ServiceException)) {
try {
SystemLog systemLog =getSystemLogInit(p);
systemLog.setLogType(SystemLog.LOGERROR);
systemLog.setExceptionCode(e.getClass().getName());
systemLog.setExceptionDetail(e.getMessage());
systemLogService.insert(systemLog);
} catch (Exception ex) {
logger.error("==异常通知异常==");
logger.error("异常信息:{}", ex.getMessage());
}
}
}
private SystemLog getSystemLogInit(JoinPoint p){
SystemLog systemLog = new SystemLog();
try{
//类名
String targetClass = p.getTarget().getClass().toString();
//请求的方法名
String tartgetMethod = p.getSignature().getName();
//获取类名 UserController
String classType = p.getTarget().getClass().getName();
Class<?> clazz = Class.forName(classType);
String clazzName = clazz.getName();
//请求参数名+参数值的map
Map<String, Object> nameAndArgs = getFieldsName(this.getClass(), clazzName, tartgetMethod, p.getArgs());
systemLog.setId(ApplicationUtils.getUUID());
systemLog.setDescription(getMthodRemark(p));
systemLog.setMethod(targetClass+"."+tartgetMethod);
//大家可自行百度获取ip的方法
systemLog.setRequestIp("192.168.1.104");
systemLog.setParams(JSON.toJSONString(nameAndArgs));
systemLog.setUserId(getUserId());
systemLog.setCreateTime(new Date());
}catch (Exception ex){
logger.error("==异常通知异常==");
logger.error("异常信息:{}", ex.getMessage());
}
return systemLog;
}
/**
* 通过反射机制 获取被切参数名以及参数值
*
* @param cls
* @param clazzName
* @param methodName
* @param args
* @return
* @throws NotFoundException
*/
private Map<String, Object> getFieldsName(Class cls, String clazzName, String methodName, Object[] args) throws NotFoundException {
Map<String, Object> map = new HashMap<>();
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(cls);
pool.insertClassPath(classPath);
CtClass cc = pool.get(clazzName);
CtMethod cm = cc.getDeclaredMethod(methodName);
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < cm.getParameterTypes().length; i++) {
//HttpServletRequest 和HttpServletResponse 不做处理
if(!(args[i] instanceof HttpServletRequest || args[i] instanceof HttpServletResponse)){
//paramNames即参数名
map.put(attr.variableName(i + pos), JSON.toJSONString(args[i]));
}
}
return map;
}
/**
* 获取方法的中文备注____用于记录用户的操作日志描述
* @param joinPoint
* @return
* @throws Exception
*/
private static String getMthodRemark(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
String methode = "";
for (Method m : method) {
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length) {
AnnotationLog methodCache = m.getAnnotation(AnnotationLog.class);
if (methodCache != null) {
methode = methodCache.remark();
}
break;
}
}
}
return methode;
}
private static String getUserId() {
String userId = "";
UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
if(userInfo != null){
userId = userInfo.getId();
}
return userId;
}
}
Три: использование
Добавьте только что созданную аннотацию в selectById UserInfoController.
@PostMapping("/selectById")
@AnnotationLog(remark = "查询")
public RetResult<UserInfo> selectById(@RequestParam String id) {
UserInfo userInfo = userInfoService.selectById(id);
return RetResponse.makeOKRsp(userInfo);
}
Четыре: тест
Введите localhost:8080/userInfo/selectById
получить результат
Просмотр базы данных System_log
можете посмотреть наш журнал
Пятое: оптимизация
Мы знаем, что система журналов предназначена главным образом для облегчения анализа программ и поиска исключений. Но для пользователя, пользователю все равно, поэтому мы не можем продлить время ожидания пользователя, потому что нам нужно записывать журнал, поэтому здесь мы создаем очередь для выполнения операции ведения журнала асинхронно
1: Создайте метод пакетного добавления
SystemLogMapper.xml
<insert id="insertByBatch" parameterType="java.util.List" >
insert into system_log (
id, description, method, log_type, request_ip, exception_code,
exception_detail, params, user_id, create_time
)
values
<foreach collection="list" item="item" index= "index" separator =",">
(
#{item.id,jdbcType=VARCHAR},
#{item.description,jdbcType=VARCHAR},
#{item.method,jdbcType=VARCHAR},
#{item.logType,jdbcType=VARCHAR},
#{item.requestIp,jdbcType=VARCHAR},
#{item.exceptionCode,jdbcType=VARCHAR},
#{item.exceptionDetail,jdbcType=VARCHAR},
#{item.params,jdbcType=VARCHAR},
#{item.userId,jdbcType=VARCHAR},
#{item.createTime,jdbcType=TIMESTAMP}
)
</foreach>
SystemLogMapper.java
Integer insertByBatch(List<SystemLog> list);
Сервисный уровень может относиться кАдрес облака кода, тут не пример
2: Создайте очередь хранения журнала
Создать папку core→systemlog
создать в этой папкеSystemLogQueue
package com.example.demo.core.systemlog;
import com.example.demo.model.SystemLog;
import org.springframework.stereotype.Component;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@Component
public class SystemLogQueue {
private BlockingQueue<SystemLog> blockingQueue = new LinkedBlockingQueue<>();
public void add(SystemLog systemLog) {
blockingQueue.add(systemLog);
}
public SystemLog poll() throws InterruptedException {
return blockingQueue.poll(1, TimeUnit.SECONDS);
}
}
3: Создайте потребителя для очереди журналов
package com.example.demo.core.systemlog;
import com.example.demo.model.SystemLog;
import com.example.demo.service.SystemLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Component
public class SystemLogConsumer implements Runnable{
private static Logger logger = LoggerFactory.getLogger(SystemLogConsumer.class);
public static final int DEFAULT_BATCH_SIZE = 64;
private SystemLogQueue auditLogQueue;
private SystemLogService systemLogService;
private int batchSize = DEFAULT_BATCH_SIZE;
private boolean active = true;
private Thread thread;
@PostConstruct
public void init() {
thread = new Thread(this);
thread.start();
}
@PreDestroy
public void close() {
active = false;
}
@Override
public void run() {
while (active) {
execute();
}
}
public void execute() {
List<SystemLog> systemLogs = new ArrayList<>();
try {
int size = 0;
while (size < batchSize) {
SystemLog systemLog = auditLogQueue.poll();
if (systemLog == null) {
break;
}
systemLogs.add(systemLog);
size++;
}
} catch (Exception ex) {
logger.info(ex.getMessage(), ex);
}
if (!systemLogs.isEmpty()) {
try {
//休眠10秒来模拟业务复杂,正在计算,测试之后大家别忘记删除这句话
Thread.sleep(10000);
systemLogService.insertByBatch(systemLogs);
}catch (Exception e){
logger.error("异常信息:{}", e.getMessage());
}
}
}
@Resource
public void setAuditLogQueue(SystemLogQueue auditLogQueue) {
this.auditLogQueue = auditLogQueue;
}
@Resource
public void setAuditLogService(SystemLogService systemLogService) {
this.systemLogService = systemLogService;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
}
4: Изменить аспект AspectLog
будет:
@Resource
private SystemLogService systemLogService;
изменить на:
@Resource
private SystemLogQueue systemLogQueue;
будет:
systemLogQueue.insert(systemLog);
изменить на:
systemLogQueue.add(systemLog);
5: тест
Введите localhost:8080/userInfo/selectById
Примечание. Это для немедленного возврата результата, не дожидаясь 10 секунд, открытия базы данных через 10 секунд и получения журнала, который мы только что обработали.
адрес проекта
Адрес облака кода:git ee.com/bean также/no SPR…
Адрес гитхаба:GitHub.com/my bean also/no s…
Писать статьи непросто, если это вам поможет, нажмите звездочку
конец
Добавление функции асинхронного ведения журнала aop завершено, и последующие функции будут обновляться одна за другой.Если у вас есть какие-либо вопросы, свяжитесь со мной по адресу mr_beany@163.com. Также попросите руководства у всех великих богов, спасибо всем.