多线程异步操作日志

上次写的一篇博客,多线程异步操作日志不完整,现在写一个完整的

功能是:用户访问一个controller,将访问的记录保存到队列中去,在开启定时器,消费掉记录保存到文件中(可改为保存到数据库)

我的idea目录:

controller中的代码:

package com.tencent.concurrent_log.controller;

import com.tencent.concurrent_log.model.LogEntity;
import com.tencent.concurrent_log.service.UrlVisitService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UrlVisitController {

    private static final Logger LOG = LoggerFactory.getLogger(UrlVisitController.class);

    @Autowired
    private UrlVisitService urlVisitService;

    @RequestMapping(value = "/visit/{url}",method = RequestMethod.GET)
    @ResponseBody
    public String urlvisit(@PathVariable String url){

        Integer userId = 666;
         String ip = null;
         String cookieValue = null;
        LogEntity entity = initEntity(userId, ip, cookieValue, url);

        try {
            urlVisitService.operLog(entity);
           return "ok";
        } catch (Exception e) {
           LOG.error("urlvisit<|>url:"+url,e.getMessage(),e);
            return "fail";
        }
    }

    private LogEntity initEntity(Integer userId,String ip,String cookieValue,String url){
        LogEntity entity = new LogEntity(null, null, url, ip, cookieValue, userId);
        return entity;
    }

}

service的实现类:

package com.tencent.concurrent_log.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tencent.concurrent_log.logthread.LogThreadPool;
import com.tencent.concurrent_log.model.LogEntity;
import com.tencent.concurrent_log.service.UrlVisitService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

@Service
public class UrlVisitServiceImpl implements UrlVisitService {

    private static final Logger LOG = LoggerFactory.getLogger("db");

    private static ObjectMapper mapper = new ObjectMapper();


    /**
    获取到线程池
     */
    @Autowired
    private LogThreadPool logThreadPool;

    @Override
    public LogEntity operLog(LogEntity entity) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(new Date());
        try {
            entity.setCreateTime(dateFormat.parse(dateString));
            //将日志信息保存到队列中
            logThreadPool.pushLog(entity);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return entity;
    }
}

实体类:

package com.tencent.concurrent_log.model;

import java.io.Serializable;
import java.util.Date;

public class LogEntity implements Serializable {
    /**
     * 指定序列化id
     */
    private static final long serialVersionUID = -5809782578272943999L;


    private Integer id;
    private Date createTime;
    private String url;
    private String ip;
    private String cookieValue;
    private Integer userId;

    public LogEntity() {
    }

    public LogEntity(Integer id, Date createTime, String url, String ip, String cookieValue, Integer userId) {
        this.id = id;
        this.createTime = createTime;
        this.url = url;
        this.ip = ip;
        this.cookieValue = cookieValue;
        this.userId = userId;
    }

    @Override
    public String toString() {
        return "LogEntity{" +
                "id=" + id +
                ", createTime=" + createTime +
                ", url='" + url + '\'' +
                ", ip='" + ip + '\'' +
                ", cookieValue='" + cookieValue + '\'' +
                ", userId=" + userId +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getCookieValue() {
        return cookieValue;
    }

    public void setCookieValue(String cookieValue) {
        this.cookieValue = cookieValue;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }
}

线程池的类:

package com.tencent.concurrent_log.logthread;

import com.tencent.concurrent_log.executor.LogWorker;
import com.tencent.concurrent_log.model.LogEntity;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
public class LogThreadPool {

    private  ThreadPoolExecutor poolExecutor;
    BlockingQueue blockingQueue = null;


    public ThreadPoolExecutor getPoolExecutor(){
        return this.poolExecutor;
    }

    /**
     * 初始化线程池
     */
    @PostConstruct
    public void initPool(){
        blockingQueue = new LinkedBlockingQueue<>(5);
        poolExecutor = new ThreadPoolExecutor(10,15,100,TimeUnit.MILLISECONDS,blockingQueue);
    }

    /**
     * 大小
     * @return
     */
    public int getPoolSize(){
        return poolExecutor.getPoolSize();
    }


    /**
     * 入队
     * @param entity
     * @throws Exception
     */
    public void pushLog(LogEntity entity) throws Exception {
        //将日志信息保存到队列中去,使用put(会造成阻塞)
        blockingQueue.put(new LogWorker(entity));
    }

    /**
     * 出队
     * @return
     */
    public Runnable poll(){
        //从队列中取出任务,使用poll(会造成阻塞)
        Runnable poll = (Runnable) blockingQueue.poll();
        return poll;
    }
}

队列中的任务类:

package com.tencent.concurrent_log.executor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tencent.concurrent_log.model.LogEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 执行日志的操作
 */
public class LogWorker implements Runnable{

    private static final Logger LOG = LoggerFactory.getLogger(LogWorker.class);

    private LogEntity entity;

    public LogWorker(LogEntity entity) {
        this.entity = entity;
    }
    public LogWorker() {
    }

    private static ObjectMapper mapper = new ObjectMapper();

    @Override
    public void run() {
        //将日志保存到文件中去
        FileWriter writer = null;
        String jsonLog = null;
        String filePath = "D:\\test\\logTest.txt";
        try {
            File file = new File(filePath);
            writer = new FileWriter(file,true);
            jsonLog = mapper.writeValueAsString(entity);
            writer.write(jsonLog);
            writer.write("\r\n");
        } catch (Exception e) {
            LOG.error("run<|>jsonLog:"+jsonLog,e.getMessage(),e);
        }finally {
            if(writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    LOG.error("run<|>jsonLog:"+jsonLog,e.getMessage(),e);
                }
            }
        }
    }
}

定时器类:

package com.tencent.concurrent_log.timer;

import com.tencent.concurrent_log.logthread.LogThreadPool;
import com.tencent.concurrent_log.service.UrlVisitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.ThreadPoolExecutor;

@EnableScheduling
@Component
public class LogTime {
    @Autowired
    private LogThreadPool logThreadPool;

    @Autowired
    private UrlVisitService urlVisitService;
    @Scheduled(cron = "0 0/1 * * * ?")
    public void logOper(){
        ThreadPoolExecutor poolExecutor = logThreadPool.getPoolExecutor();
        Runnable runnable = logThreadPool.poll();
        System.out.println(poolExecutor.hashCode());
        if(null != runnable){
         poolExecutor.submit(runnable);
        }
    }
}

log4j的配置,log4j.properties


log4j.rootLogger=DEBUG,console
#自定义路径
log.rootdir =/data/logs/shortlink/

#自定义日志输出文件
log4j.logger.db=INFO,db
log4j.appender.db.Threshold = INFO
#log4j.appender.db.Append=false
#配置文件保存的时间是每天更新
log4j.appender.db=org.apache.log4j.DailyRollingFileAppender
#配置路径(使用自定义路径)
log4j.appender.db.File = ${log.rootdir}/visit
#log4j.appender.db.File = D:/logs/visit
#自定义文件名
log4j.appender.db.DatePattern= '_'yyyy-MM-dd'.log'
log4j.appender.db.Encoding=UTF-8
log4j.appender.db.layout=org.apache.log4j.PatternLayout
log4j.appender.db.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss}[ %p ]%m%n

直接测试,可以看到文件中增加了日志信息

猜你喜欢

转载自blog.csdn.net/qq_42151769/article/details/84065904