业务完成后日志入库,如果串行操作会影响业务效率。
所以采用AOP进行日志信息的切面拦截,并且使用队列进行入库操作。
package com.java.main.base.aspect;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.java.main.auth.model.MobileUserAuthInfo;
import com.java.main.base.service.LogService;
import com.java.main.base.queue.InterfaceLogSaveQueue;
import com.java.main.utils.TimeUtils;
/**
* 日志记录-webService
* @author Administrator
*
*/
@Component
@Aspect
public class LogServiceAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
@Autowired
private HttpSession session;
@Autowired
private LogService webServiceLogService;
/**
* 系统接口切面
* @param pjp
* @return
* @throws Throwable
*/
@Around("@annotation(com.java.main.base.annotation.SystemInterfaceLog)")
public Object systemInterfaceLogAround(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
logger.info("LogServiceAspect SystemInterfaceLog: " + methodName + "----------开始");
Object[] args = pjp.getArgs();
String className = pjp.getSignature().getDeclaringTypeName();
String operationStartTime = TimeUtils.getCurrentDate("yyyy-MM-dd hh:mm:ss");
Object result = pjp.proceed();
Map<String, Object> map = new HashMap<String, Object>();
//webService
if(className.equals("com.java.main.base.service.impl.WSInvokeServiceImpl")) {
MobileUserAuthInfo mus = (MobileUserAuthInfo) session.getAttribute("mobileUserAuthSession");
map.put("loginName", mus.getLoginName());
map.put("fullName", mus.getFullName());
map.put("depId", mus.getDepId());
map.put("depName", mus.getDepName());
map.put("operationSystem", mus.getAccessAppName());
map.put("type", args[0]);
map.put("returnXml", result);
map.put("operationStartTime", operationStartTime);
//处理入参
Map<String, String> paramsMap = new HashMap<String, String>();
String[] paramNames = (String[]) args[1];
String[] params = (String[]) args[2];
for(int i = 0 ; i < paramNames.length ; i++) {
paramsMap.put(paramNames[i], params[i]);
}
map.put("params", JSONObject.fromObject(paramsMap).toString());
}
//日志数据入队
InterfaceLogSaveQueue.getInstance().add(map);
logger.info("LogServiceAspect SystemInterfaceLog: " + methodName + "----------结束");
return result;
}
/**
* 应用访问切面
* @param pjp
* @return
* @throws Throwable
*/
@Around("@annotation(com.java.main.base.annotation.AppAccessLog)")
public Object appAccessLogAround(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
logger.info("LogServiceAspect AppAccessLog: " + methodName + "----------开始");
String className = pjp.getSignature().getDeclaringTypeName();
String operationStartTime = TimeUtils.getCurrentDate("yyyy-MM-dd hh:mm:ss");
Object result = pjp.proceed();
Map<String, Object> map = new HashMap<String, Object>();
if(className.equals("com.java.main.email.service.impl.EmailAuthServiceImpl")) {
MobileUserAuthInfo mus = (MobileUserAuthInfo) session.getAttribute("mobileUserAuthSession");
map.put("loginName", mus.getLoginName());
map.put("fullName", mus.getFullName());
map.put("depId", mus.getDepId());
map.put("depName", mus.getDepName());
map.put("operationSystem", mus.getAccessAppName());
map.put("operationSystem", "邮箱");
map.put("type", "邮箱入口");
map.put("operationStartTime", operationStartTime);
}
//日志数据入队
InterfaceLogSaveQueue.getInstance().add(map);
logger.info("LogServiceAspect AppAccessLog: " + methodName + "----------结束");
return result;
}
}
InterfaceLogSaveQueue队列进行日志数据的add操作。
package com.java.main.base.queue;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.java.main.common.constants.PropertiesUtils;
/**
* 接口日志队列
* @author Administrator
*
*/
public class InterfaceLogSaveQueue {
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
private static final InterfaceLogSaveQueue interfaceLogQueue = new InterfaceLogSaveQueue();
//队列容量
private int size = getPoolSize();
//阻塞队列
private final BlockingQueue<Map<String, Object>> queue = new LinkedBlockingQueue<Map<String, Object>>(size);
private InterfaceLogSaveQueue() {}
public static InterfaceLogSaveQueue getInstance() {
return interfaceLogQueue;
}
private int getPoolSize() {
String sizeStr = PropertiesUtils.getProperty("queue.interface.log.save.pool.size");
sizeStr = Optional.ofNullable(sizeStr).filter(s -> !s.equals("")).orElse("0");
logger.info("接口日志队列-容量:" + sizeStr);
return Integer.parseInt(sizeStr);
}
public void add(Map<String, Object> map) {
logger.info("【接口日志队列】【入列操作】=" + map);
//队列满了抛出异常
try {
queue.add(map);
} catch (Exception e) {
e.printStackTrace();
}
}
public Map<String, Object> take() {
try {
Map<String, Object> m = queue.take();
logger.info("【接口日志队列】【出列操作】=" + m);
return m;
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
队列初始化容量自定义(默认1000),add操作队列满抛出异常。如果这里阻塞会影响其他业务操作。抛出异常更为合理,更改适当的容量。
package com.java.main.base.queue;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.java.main.base.service.LogService;
import com.java.main.common.constants.PropertiesUtils;
import com.java.main.common.core.util.WebApplicationManager;
/**
* 接口日志消费类
* @author Administrator
*
*/
public class InterfaceLogSaveCustomer implements Runnable {
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
private InterfaceLogSaveQueue interfaceLogQueue;
@Autowired
private LogService webServiceLogService;
public void startThread() {
String sizeStr = PropertiesUtils.getProperty("queue.interface.log.save.customer.size");
sizeStr = Optional.ofNullable(sizeStr).filter(s -> !s.equals("")).orElse("0");
logger.info("接口日志队列-消费者启动....");
logger.info("接口日志队列-消费数量:" + sizeStr);
int size = Integer.parseInt(sizeStr);
ExecutorService executor = Executors.newFixedThreadPool(size);
for(int i = 0; i < size; i++) {
executor.execute(new InterfaceLogSaveCustomer());
}
}
public InterfaceLogSaveCustomer() {
webServiceLogService = (LogService) WebApplicationManager.getBean("webServiceLogService");
interfaceLogQueue = InterfaceLogSaveQueue.getInstance();
}
@Override
public void run() {
while(true) {
if(webServiceLogService != null) {
webServiceLogService.addLog(interfaceLogQueue.take());
}
}
}
}
InterfaceLogSaveCustomer类自定义消费者数量。
在系统启动初始化操作(也可以使用注解方式):
new InterfaceLogSaveCustomer().startThread();
这里使用的是ServletContextListener