最近有个需求需要记录用户操作记录,实现起来无非是用aop直接记录日志。用自定义注解,通过属性文件建立注解和具体操作的映射关系,然后用aop切入持有该注解的接口,记录操作信息。
这种在并发不高的系统上是可行的,一旦并发量略高,aop里的插入DB操作势必会影响接口响应时间,对性能影响还是有一些的。因此将其改为系统定时批量插入日志,模拟一个简单的mq,下面直接贴代码。具体实现全写在注释里了。
//@Component
public class TaskThreadPools {
@Autowired
private ManagerService managerService;
@Autowired
private OperationLogService operationLogService;
private static final org.apache.commons.logging.Log log = LogFactory.getLog(TaskThreadPools.class);
//线程池对队列的操作可能并发,需要volatile保证队列内存可见性
private static volatile Queue<QueueDealStructure> dataQueue;
private volatile List<OperationLog> logs = Collections.synchronizedList(new ArrayList<>());
public static Queue<QueueDealStructure> getQueueInstance() {
if (dataQueue == null) {
//LinkedList实现了Queue接口,可以用LinkedList做一个队列,这里使用阻塞队列BlockingQueue
dataQueue = new LinkedBlockingQueue<>();
}
return dataQueue;
}
public void commitLogPool() {
/**
*@Author hfismyangel@163.com
*@Description:定时任务线程池自动提交日志
*@Date: 20:01 2017/10/13
* @param
*/
if (getQueueInstance().peek() != null) {
log.info("===================poll is not null,make Executor>>");
int size;
//初始化固定容量为队列长度的Executor
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool((size = getQueueInstance().size()));
for (int i = 0; i < size; i++) {
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
QueueDealStructure poll;
if ((poll = getQueueInstance().poll()) != null) {
try {
String keyIdentity = poll.getKeyIdentity();
String property = poll.getProperty();
log.info("===================thread start and Thread id>>" + Thread.currentThread().getId());
Long adminId = Long.valueOf(keyIdentity);
Manager admin = managerService.getObjectById(adminId);
//创建日志对象
OperationLog operationLog = new OperationLog();
operationLog.setAdmin(admin.getName());
operationLog.setOperation(property);
operationLog.setCreateBy(adminId);
operationLog.setUpdateBy(adminId);
logs.add(operationLog);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
//及时关闭,否则可能引起内存泄露
threadPoolExecutor.shutdown();
if (logs.size() != 0) {
try {
//批量插入
operationLogService.insertList(logs);
log.info("==================insert database finish>>");
logs.clear();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Scheduled(cron = "0 0 0/1 * * ?")
public void timer() {
//spring timer定时提交任务
commitLogPool();
}
}