精华内容
下载资源
问答
  • 主要介绍了java异步写日志到文件中实现代码的相关资料,需要的朋友可以参考下
  • java异步写日志到文件中

    千次阅读 2017-01-17 17:04:55
    直接上代码了,一共3个类。       ...import java.io.File;...import java.io.FileWriter;...import java.io.IOException;...import java.io.InputStream;...import java.io.PrintWriter;...import java.util.

    直接上代码了,一共3个类。

     

     

     

    package com.tydic.ESUtil;
    
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.PrintWriter;
    import java.util.Properties;
    
    public class LogWriter {
    //  日志的配置文件
    	public static final String LOG_CONFIGFILE_NAME = "log.properties";
    	//  日志文件名在配置文件中的标签
    	public static final String LOGFILE_TAG_NAME = "logfile";
    	
    	//	默认的日志文件的路径和文件名称
    	private final String DEFAULT_LOG_FILE_NAME = "./logtext.log";
    	//	该类的唯一的实例
    	private static LogWriter logWriter;
    	//  文件输出流
    	private PrintWriter writer;  
    	//  日志文件名
    	private String logFileName; 
    	/**
    	 * 默认构造函数
    	 */
    	private LogWriter() throws LogException{
    		this.init();
    	}
    	private LogWriter(String fileName) throws LogException{
    		this.logFileName = fileName;
    		this.init();
    	}
    	/**
    	 * 获取LogWriter的唯一实例。
    	 * @return
    	 * @throws LogException
    	 */
    	public synchronized static LogWriter getLogWriter()throws LogException{
    		if (logWriter == null){
    			logWriter = new LogWriter();
    		}
    		return logWriter;
    	}
    	public synchronized static LogWriter getLogWriter(String logFileName)throws LogException{
    		if (logWriter == null){
    			logWriter = new LogWriter(logFileName);
    		}
    		return logWriter;
    	}
    
    	/**
    	 * 往日志文件中写一条日志信息
    	 * 为了防止多线程同时操作(写)日志文件,造成文件”死锁”。使用synchronized关键字
    	 * @param logMsg	日志消息
    	 */
    	public synchronized void log(String logMsg) {
    		this.writer.println(new java.util.Date() + ": " + logMsg);
    	}
    	/**
    	 * 往日志文件中写一条异常信息
    	 * 使用synchronized关键字。
    	 * @param ex	待写入的异常
    	 */
    	public synchronized void log(Exception ex) {
    		writer.println(new java.util.Date() + ": ");
    		ex.printStackTrace(writer);
    	}
    
    	/**
    	 * 初始化LogWriter
    	 * @throws LogException
    	 */
    	private void init() throws LogException{
    		//如果用户没有在参数中指定日志文件名,则从配置文件中获取。
    		if (this.logFileName == null){
    			this.logFileName = this.getLogFileNameFromConfigFile();
    			//如果配置文件不存在或者也没有指定日志文件名,则用默认的日志文件名。
    			if (this.logFileName == null){
    				this.logFileName = DEFAULT_LOG_FILE_NAME;
    			}
    		}
    		File logFile = new File(this.logFileName);
    		try {
    			//	其中的FileWriter()中的第二个参数的含义是:是否在文件中追加内容
    			//  PrintWriter()中的第二个参数的含义是:自动将数据flush到文件中
    			writer = new PrintWriter(new FileWriter(logFile, true), true);
    			System.out.println("日志文件的位置:" + logFile.getAbsolutePath());
    		} catch (IOException ex) {
    			String errmsg = "无法打开日志文件:" + logFile.getAbsolutePath();
    			//  System.out.println(errmsg);
    			throw new LogException(errmsg, ex);
    		}
    	}
    	/**
    	 * 从配置文件中取日志文件名
    	 * @return
    	 */
    	private String getLogFileNameFromConfigFile() { 
    		try { 
    			Properties pro = new Properties(); 
    			//在类的当前位置,查找属性配置文件log.properties 
    			InputStream fin = getClass().getResourceAsStream(LOG_CONFIGFILE_NAME); 
    			if (fin != null){
    				pro.load(fin);//载入配置文件
    				fin.close(); 
    				return pro.getProperty(LOGFILE_TAG_NAME);
    			} else {
    				System.err.println("无法打开属性配置文件: log.properties" ); 
    			}
    		}catch (IOException ex) { 
    			System.err.println("无法打开属性配置文件: log.properties" ); 
    		}
    		return null;
    	}
    	//关闭LogWriter
    	public void close() {
    		logWriter = null;
    		if (writer != null){
    			writer.close();
    		}
    	}
    
    	public static void main(String[] args) {
    		LogWriter logger = null;
    		try {
    			String fileName = "d:/temp/logger.log";
    			logger = LogWriter.getLogWriter(fileName);
    //			logger.log("First log!");
    //			logger.log("第二个日志信息");
    //			logger.log("Third log");
    //			logger.log("第四个日志信息");
    		   	String content="tableaA|device_number|13701010";
    		   	StringBuffer sb=new StringBuffer();
    		   	for(int i=0;i<1000000;i++){
    		   		sb.append(content).append(i).append(";\n");
    		   	}
    		   	content=sb.toString();
    		   	long startTime=System.currentTimeMillis();
    		   	logger.log(content);
    			long endTime=System.currentTimeMillis();
    			System.out.println("总消耗时间:"+(endTime-startTime));
    			logger.close();
    //			ReadFromFile.readFileByLines(fileName);
    		} catch (LogException e) {
    			e.printStackTrace();
    		}
    	}
    }
    


     

     

    package com.tydic.ESUtil;
    
    public class AychWriter extends Thread {
    	private String content;
    	public AychWriter(String content){
    		this.content=content;
    	}
    	@Override
    	public void run(){
    		System.out.println("开始执行run()");
    		LogWriter logger = null;
    		String fileName = "d:/temp/logger.log";
    	   	long startTime=System.currentTimeMillis();
    		try {
    			logger = LogWriter.getLogWriter(fileName);
    			logger.log(this.content);
    		} catch (LogException e1) {
    			// TODO Auto-generated catch block
    			e1.printStackTrace();
    		}
    
    		long endTime=System.currentTimeMillis();
    		System.out.println("总消耗时间:"+(endTime-startTime));
    	}
    }
    


     

    测试类:

    package com.tydic.ESUtil;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    import org.junit.Test;
    
    public class test_test {
    	/**
    	 * 同步向指定文件尾部写入字符串
    	 */
    public  void testAppendMethodB(String fileName,String content) throws IOException{
    		try {
    			//打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件
    			FileWriter writer = new FileWriter(fileName, true);
    			writer.write(content);
    			writer.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		}
    
    /**
     *调用上面同步写方法 
     */
    	@Test
    	public void testWriteTOFile() throws IOException{
    		String fileName = "d:\\test.txt";
    	   	String content="tableaA|device_number|13701010";
    	   	StringBuffer sb=new StringBuffer();
    	   	for(int i=0;i<100000;i++){
    	   		sb.append(content).append(i).append(";\n");
    	   	}
    	   	content=sb.toString();
    	   	long startTime=System.currentTimeMillis();
    	   	testAppendMethodB(fileName,content);
    		long endTime=System.currentTimeMillis();
    		System.out.println("总消耗时间:"+(endTime-startTime));
    	}
    	/**
    	 * 异步调用写方法
    	 * @throws IOException
    	 * @throws InterruptedException
    	 */
    	@Test
    	public void testAsyncWriteTOFile() throws IOException, InterruptedException{
    		String fileName = "d:\\test.txt";
    	   	String content="tableaA|device_number|13701010";
    	   	StringBuffer sb=new StringBuffer();
    	   	for(int i=0;i<100000;i++){
    	   		sb.append(content).append(i).append(";\n");
    	   	}
    	   	content=sb.toString();
    	   	System.out.println("start write...");
    	   	new AychWriter(content).start();
    	   	System.out.println("write over...");
    	   	Thread.sleep(30000); //重要,如果主线程挂了,调用线程也停止了
    	   	System.out.println("main Thread over");
    	}
    	
    }
    


     

     

    展开全文
  • 异步写日志

    2011-09-15 00:40:42
    一个函数内可能有很多写日志的地方,会大大增加方法返回的时间,异步写日志,可以提高函数的执行效率。
  • Java异步日志使用介绍

    2013-11-22 12:38:40
    近期开发了一个API供第三方使用接入...通过观察日志,发现代码执行比较慢,但是非常随机,有时候从一个方法进入之前和进入之后都需要花费100ms。为什么会这样呢? 经过分析,定位到是logback同步日志输出在压力比...

    近期开发了一个API供第三方使用接入开放平台。第三方在做压力测试时,发现平均响应时间在1m以上,不能满足他们的TPS

    在关键处理环节加上了日志输出。本人使用的日志实现是logback,经过实际测试比log4j性能要好。通过观察日志,发现代码执行比较慢,但是非常随机,有时候从一个方法进入之前和进入之后都需要花费100ms。为什么会这样呢?

    经过分析,定位到是logback同步日志输出在压力比较大的时候占用了执行时间。后来在网上查询是否有logback异步日志使用的样例,通过Baidu没有搜到,后来到了logback官网找到了异步日志的实现。

    经过时间测试,在压力测试(10000人登陆,TPS2000,平均响应时间100ms),持续10分钟压测,异步日志产生日志4G数据量但几乎没有对性能造成太大的影响。

     

    AsyncAppender介绍使用现摘录如下:

    URLhttp://logback.qos.ch/manual/appenders.html#AsyncAppender

     

    AsyncAppender logs ILoggingEvents asynchronously. It acts solely as an event dispatcher and must therefore reference another appender in order to do anything useful.

    Lossy by default if 80% full AsyncAppender buffers events in a BlockingQueue. A worker thread created by AsyncAppender takes events from the head of the queue, and dispatches them to the single appender attached to AsyncAppender. Note that by default, AsyncAppender will drop events of level TRACE, DEBUG and INFO if its queue is 80% full. This strategy has an amazingly favorable effect on performance at the cost of event loss.

    Application stop/redeploy Upon application shutdown or redeploy, AsyncAppender must be stopped in order to stop and reclaim the worker thread and to flush the logging events from the queue. This can be achieved by stopping the LoggerContext which will close all appenders, including any AsyncAppender instances.

    Here is the list of properties admitted by AsyncAppender:

    Property Name

    Type

    Description

    queueSize

    int

    The maximum capacity of the blocking queue. By default, queueSize is set to 256.

    discardingThreshold

    int

    By default, when the blocking queue has 20% capacity remaining, it will drop events of level TRACE, DEBUG and INFO, keeping only events of level WARN and ERROR. To keep all events, set discardingThreshold to 0.

    includeCallerData

    boolean

    Extracting caller data can be rather expensive. To improve performance, by default, caller data associated with an event is not extracted when the event added to the event queue. By default, only "cheap" data like the thread name and the MDC are copied. You can direct this appender to include caller data by setting the includeCallerData property to true.

    By default, event queue is configured with a maximum capacity of 256 events. If the queue is filled up, then application threads are blocked from logging new events until the worker thread has had a chance to dispatch one or more events. When the queue is no longer at its maximum capacity, application threads are able to start logging events once again. Asynchronous logging therefore becomes pseudo-synchronous when the appender is operating at or near the capacity of its event buffer. This is not necessarily a bad thing. The appender is designed to allow the application to keep on running, albeit taking slightly more time to log events until the pressure on the appenders buffer eases.

    Optimally tuning the size of the appenders event queue for maximum application throughput depends upon several factors. Any or all of the following factors are likely to cause pseudo-synchronous behavior to be exhibited:

    • Large numbers of application threads
    • Large numbers of logging events per application call
    • Large amounts of data per logging event
    • High latency of child appenders

    To keep things moving, increasing the size of the queue will generally help, at the expense of heap available to the application.

    Lossy behavior In light of the discussion above and in order to reduce blocking, by default, when less than 20% of the queue capacilty remains, AsyncAppender will drop events of level TRACE, DEBUG and INFO keeping only events of level WARN and ERROR. This strategy ensures non-blocking handling of logging events (hence excellent performance) at the cost loosing events of level TRACE, DEBUG and INFO when the queue has less than 20% capacity. Event loss can be prevented by setting the discardingThreshold property to 0 (zero).

    Example: AsyncAppender configuration (logback-examples/src/main/java/chapters/appenders/conc/logback-async.xml)

    View as .groovy

    <configuration>
      <appendername="FILE"class="ch.qos.logback.core.FileAppender">
        <file>myapp.log</file>
        <encoder>
          <pattern>%logger{35} - %msg%n</pattern>
        </encoder>
      </appender>
      <appendername="ASYNC"class="ch.qos.logback.classic.AsyncAppender">
        <appender-refref="FILE"/>
      </appender>
      <rootlevel="DEBUG">
        <appender-refref="ASYNC"/>
      </root>
    </configuration>

     

    展开全文
  • Java之手写异步任务

    万次阅读 2020-04-03 09:47:28
    比如在用户操作软件的时候需要记录一些操作日志,频繁写入db的操作会影响用户体验。 实现思路: 首先创建一个AbstractQueue类,用于存放任务队列。然后创建一个AbstractAsynTask类,用于管理AbstractQueue队列。 ...

        为什么需要异步任务?有些代码可能影响程序性能,并且不需要实时同步执行,这部分代码就可以放到异步任务中,以减少响应时间。比如在用户操作软件的时候需要记录一些操作日志,频繁写入db的操作会影响用户体验。

    实现思路: 首先创建一个AbstractQueue类,用于存放任务队列。然后创建一个AbstractAsynTask类,用于管理AbstractQueue队列。

    下面是具体实现:

     

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.Queue;
    import java.util.concurrent.ConcurrentLinkedQueue;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * @Author: jack
     * @Description:抽象异步队列
     */
    public abstract class AbstractQueue {
    
        private static Logger log = LoggerFactory.getLogger(AbstractQueue.class);
    
        //队列空闲时间  3分钟
        private static final int timeout = 3 * 60 * 1000 ;
    
        //当前任务大小
        private volatile AtomicInteger size = new AtomicInteger();
    
        //线程启动开关
        private boolean isRun = false;
    
        private volatile Queue<Object> queue = new ConcurrentLinkedQueue();
    
        //线程,用于遍历队列
        private volatile Thread thread = null;
    
        //最后执行时间
        private volatile long lastTime = System.currentTimeMillis();
    
        //队列名称
        public String queueName = "抽象队列";
    
        //线程结果汇总
        private volatile StringBuilder resultBuilder = new StringBuilder();
    
        //总数
        private volatile AtomicInteger total = new AtomicInteger();
    
        //成功数
        private volatile AtomicInteger success = new AtomicInteger();
    
        //失败数
        private volatile AtomicInteger fail = new AtomicInteger();
    
        public void add(Object dto) {
            queue.add(dto);
            size.incrementAndGet();
            total.incrementAndGet();
        }
    
        private void stop() {
            log.error("【" + queueName + "】,线程关闭");
            isRun = false;
            resultBuilder.append("总数:" + total.intValue() + ",成功数:" + success.intValue() + ",失败数:" + fail.intValue());
            log.error(resultBuilder.toString());
        }
    
        private void start() {
            log.error("【" + queueName + "】,线程开启");
            isRun = true;
            thread.start();
    
        }
    
        public int getSize() {
            return size.get();
        }
    
        public AbstractQueue(String queueName) {
            this.queueName = queueName;
            resultBuilder.append("【" + queueName + "】,执行汇总:").append("\r\n");
    
            thread = new Thread(() -> {
                while (isRun) {
                    Object emailDto = null;
                    try {
                        if (!queue.isEmpty()) {
                            lastTime = System.currentTimeMillis();
                            emailDto = queue.poll();
                            size.decrementAndGet();
    
                            task(emailDto);
    
                            success.incrementAndGet();
                        }
    
                        long currentTime = System.currentTimeMillis();
                        if ((currentTime - lastTime) >= timeout) {
                            stop();
                        } else {
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        fail.incrementAndGet();
                    }
                }
            });
    
            start();
        }
    
        abstract public void task(Object dto);
    
        public boolean isAlive() {
            return thread.isAlive() && isRun;
        }
    }
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    /**
     * @Author: jack
     * @Description:抽象异步任务
     */
    public abstract class AbstractAsynTask {
        //每个队列最大容量
        public static final int max_capacity = 500;
    
        //队列列表
        public volatile List<AbstractQueue> queueList =new ArrayList<>();
    
        public void add(Object dto){
            boolean isAdd = false;
    
            Iterator ite = queueList.iterator();
            while(ite.hasNext()){
                AbstractQueue queue = (AbstractQueue) ite.next();
                if(queue.getSize() >= max_capacity){
                    continue;
                }
    
                if(!queue.isAlive()){
                    ite.remove();
                    queueList.add(createNewQueue());
                }
    
                queue.add(dto);
                isAdd = true;
                break;
            }
    
            if(!isAdd){
                AbstractQueue queue = doCreateNewQueue();
                queue.add(dto);
                queueList.add(queue);
            }
        }
    
        public AbstractQueue doCreateNewQueue(){
            return createNewQueue();
        }
    
        abstract public AbstractQueue createNewQueue();
    
        public int getQueueSize(){
            return queueList.size();
        }
    
    }

      到这已经大功告成了,接下来写个具体实现,测试一下异步任务。

    public class SendMsgQueue extends AbstractQueue {
    
        @Override
        public void task(Object dto) {
            try {
                System.out.println("【"+queueName+"】"+"sending content :"+dto);
                Thread.sleep(50);
                System.out.println("【"+queueName+"】"+"send finish...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public SendMsgQueue(String queueName){
            super(queueName);
        }
    }
    public class SendMsgAsynTask extends AbstractAsynTask {
    
        @Override
        public AbstractQueue createNewQueue() {
            return new SendMsgQueue("消息队列"+getQueueSize());
        }
    }
    

    然后是测试类

    public class test {
    
        public static void main(String[] args) {
            SendMsgAsynTask task = new SendMsgAsynTask();
            for(int i=0;i<10000;i++){
                task.add("hello world");
            }
        }
    }

    执行后控制台部分输出如下

    [ERROR]-[Thread: main]-[com.recovery.www.task.asyn.AbstractQueue.start()]: 【消息队列17】,线程开启
    【消息队列16】sending content :hello world
    【消息队列17】sending content :hello world
    
    2020-04-03 09:39:56
    [ERROR]-[Thread: main]-[com.recovery.www.task.asyn.AbstractQueue.start()]: 【消息队列18】,线程开启
    【消息队列18】sending content :hello world
    
    2020-04-03 09:39:56
    [ERROR]-[Thread: main]-[com.recovery.www.task.asyn.AbstractQueue.start()]: 【消息队列19】,线程开启
    【消息队列19】sending content :hello world
    【消息队列0】send finish...
    【消息队列1】send finish...
    【消息队列2】send finish...

    可以看到执行10000个任务总共开启了19个线程。这些任务在线程中串行执行

    展开全文
  • 下面就以异步记录访问日志为例通过Redis实现简单的消息队列异步记录系统访问日志。 原理:记录日志时通过lpush放入list中,开启一个线程监听这个list,如果list没有记录则线程阻塞。 我的项目采用ssm+jedis spring...

    通过Redis实现消息队列主要用的是Redis数据类型List,Lpush,Brpop两个命令。Redis实现的消息队列肯定不如MQ的功能强大,灵活。但是实现一些不复杂的生产者-消费者模型还是可以参考的。毕竟不用单独搭建一套MQ。

    Lpush:命令将一个或多个值插入到列表头部。 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。 当 key 存在但不是列表类型时,返回一个错误。

    Brpop :命令移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

    下面就以异步记录访问日志为例通过Redis实现简单的消息队列异步记录系统访问日志。

    原理:记录日志时通过lpush放入list中,开启一个线程监听这个list,如果list没有记录则线程阻塞。

    我的项目采用ssm+jedis

    spring配置文件:

    Redis实现类:

    package com.example.demo.redis.jedisUtils;
     
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
     
    public class JedisClientPool implements JedisClient {
        //创建JedisPool来操作单机版的数据库
        @Autowired
        private JedisPool jedisPool;
     
        @Override
        public String set(String key, String value) {
            Jedis jedis = jedisPool.getResource();
            String result = jedis.set(key, value);
            jedis.close();
            return result;
        }
     
        @Override
        public String get(String key) {
            Jedis jedis = jedisPool.getResource();
            String result = jedis.get(key);
            jedis.close();
            return result;
        }
     
        @Override
        public Boolean exists(String key) {
            Jedis jedis = jedisPool.getResource();
            Boolean result = jedis.exists(key);
            jedis.close();
            return result;
        }
     
        @Override
        public Long expire(String key, int seconds) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.expire(key, seconds);
            jedis.close();
            return result;
        }
     
        @Override
        public Long ttl(String key) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.ttl(key);
            jedis.close();
            return result;
        }
     
        @Override
        public Long incr(String key) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.incr(key);
            jedis.close();
            return result;
        }
     
        @Override
        public Long hset(String key, String field, String value) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.hset(key, field, value);
            jedis.close();
            return result;
        }
     
        @Override
        public String hget(String key, String field) {
            Jedis jedis = jedisPool.getResource();
            String result = jedis.hget(key, field);
            jedis.close();
            return result;
        }
     
        @Override
        public Long hdel(String key, String... field) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.hdel(key, field);
            jedis.close();
            return result;
        }
    
        @Override
        public long lpush(String key, String value) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.lpush(key, value);
            jedis.close();
            return result;
        }
    
        @Override
        public List<String> brpop(String key) {
            Jedis jedis = jedisPool.getResource();
            List<String> result = jedis.brpop(0, key);
            jedis.close();
            return result;
        }
     
    }

     

     

     

    线程监听处理任务类:

    package com.example.demo.redis.task;
    
    import java.util.List;
    
    import net.sf.json.JSONObject;
    
    import com.example.demo.redis.bean.RequestLogBean;
    import com.example.demo.redis.dao.RequestLogDao;
    import com.example.demo.redis.jedisUtils.JedisClient;
    
    public class WriteRequestLogTaskTask {
        private JedisClient jedis;
        private RequestLogDao requestLogDao;
        WriteRequestLogTaskTask(JedisClient jedisClient,RequestLogDao requestLogDao){
            this.jedis=jedisClient;
            this.requestLogDao=requestLogDao;
            if(jedis!=null){
                 init();
            }
        }
        private void init(){
            //这块开启了一个线程记录日志,也可以用线程池开启多个线程记录 redis 多个线程操作一个队列 也不会出现 现场安全问题的
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("日志记录线程已经启动");
                    while(true){
                        List<String>list=jedis.brpop(JedisClient.REQUEST_LOG_KEY);//brpop 如果队列为空 会一直阻塞
                        if(list!=null&&list.size()>0){
                            for(String str:list){
                                if(!JedisClient.REQUEST_LOG_KEY.equalsIgnoreCase(str)){
                                    JSONObject json=JSONObject.fromObject(str);
                                    RequestLogBean bean=(RequestLogBean)JSONObject.toBean(json,RequestLogBean.class);
                                    requestLogDao.saveLog(bean);
                                }
                                //字符串转成实体类
                                //写入数据库
                            }
                            
                        }
                    }
                    
                }
            });
            
            thread.start();
            
        }
    
    }

    记录日志:

    package com.example.demo.redis.controller;
    
    import java.io.IOException;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import net.sf.json.JSONObject;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import com.example.demo.redis.bean.RequestLogBean;
    import com.example.demo.redis.jedisUtils.JedisClient;
    
    @Controller
    @RequestMapping("/test")
    public class TestRedisController {
        @Autowired
        public JedisClient jedis;
        @RequestMapping("/redis")
        public void redis(HttpServletRequest request,HttpServletResponse response) throws IOException{
            String requestId=request.getParameter("requestid");
            String params=request.getParameter("params");
            String ip =request.getRemoteAddr();
            String result="SUCCESS";
            //业务请求逻辑
            
            //记录日志
            RequestLogBean requestLogBean=new RequestLogBean(requestId,params,result,System.currentTimeMillis()+"",ip);
            jedis.lpush(JedisClient.REQUEST_LOG_KEY, JSONObject.fromObject(requestLogBean).toString());//这块存进redis的是json字符串 有可以是其他类型,后面转成实体(如果直接存 实体类型要序列化)
            response.getWriter().write("请求成功!");
    }
    }

     

     

     

     

     

     

     

     

    展开全文
  • 什么是异步?为什么要用它? 异步编程提供了一个非阻塞的,事件驱动的编程模型。 这种编程模型利用系统中多核执行任务来提供并行,因此提供了应用的吞吐率。此处吞吐率是指在单位时间内所做任务的数量。 在这种...
  • JAVA-日志异步收集输出

    千次阅读 2019-05-24 14:49:59
    记录一下最近做的一个Web项目中的日志问题 项目使用的日志体系如下:使用sl4j作为门面,log的实际实现是log4j 问题如下: 在请求高并发的情况下,推测日志会出现串的情况。 举个例子: public void echo() ...
  • 多线程异步操作日志

    2018-11-14 14:33:10
    上次的一篇博客,多线程异步操作日志不完整,现在一个完整的 功能是:用户访问一个controller,将访问的记录保存到队列中去,在开启定时器,消费掉记录保存到文件中(可改为保存到数据库) 我的idea目录: ...
  • AsyncTask -- Java异步调用框架

    千次阅读 2017-02-28 17:40:09
    原创文章,转载请注明...  AsyncTask是个人编写的一个Java异步调用框架,支持用户: 1)自定义Task,并可设置Task的类型(Type), 子类型(subType),超时时间(TImeout),标识(Flag-可用来区分不同的Task),
  • java异步执行代码

    千次阅读 2018-03-05 16:51:00
     //这里可以一个等待方法,让当前线程等待10秒钟现象更明显  //控制台打印日志  System . out .println(Content);  } }.start(); }   public   static   void  main( String [] args...
  • java异步处理耗时请求

    千次阅读 2019-03-18 20:18:35
    模拟异步调用 import com.springdemo2.service.helloService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.spring...
  • java 异步并行框架 async-01-入门教程

    万次阅读 2019-03-12 19:49:47
    Async 是一款 Java 异步处理框架。 设计目的 并行执行可以大幅度提升程序的运行速度,有效利用 CPU 资源。 但是单独为每次方法都使用线程池手写,显然不够优雅,复用性也很差。 特性 支持接口类的动态代理异步 ...
  • 1,异步输出日志的配置 logback中的异步输出日志使用了AsyncAppender这个appender 配置方式如下: logs/context-log.%d{yyyy-MM-dd}.log 30 [%-5level] %date --%thread-- [%logger] %msg %n
  • android 异步写入日志到文件中

    千次阅读 2016-10-12 16:39:31
    文件是耗时操作,为不影响性能,需要异步线程处理.log记录是很频繁的操作,不该每次记录日志都创建线程,否则CPU开销太大,反倒影响了性能,需要保持线程常在,有需要时,再工作. 外部调用: AsyncLogger.Logging("TAG", ...
  • 获益于异步日志服务 Hibernate和JMS开发异步日志服务
  • 当我们项目中的一些非核心业务运行时,因其耗时操作,影响到用户核心业务的响应时间,此时可以将这些非核心业务的耗时操作放到新的线程中异步执行。例如: new Thread(new Runnable() { @Override public void run()...
  • ps:记录日志,可以在业务逻辑中,也可以利用aop自动记录。 ... service{ public void login(){ // 登录逻辑 ...... // 记录日志插入数据库 // 这个记录过程是要占用当前线程时间的 // 通过异步...
  • Java AIO-异步通信

    千次阅读 2016-08-04 02:25:05
    Java AIO 异步非阻塞IO示例
  • logback 异步日志配置

    千次阅读 2017-07-03 16:03:39
    目前所有的日志记录方式采用的都是同步的方式,即直接将日志写入文件。 在多应用的时候,这种效果会导致一定的...异步日志记录是在原来logback上的扩展,并不是替代方式,所以只需要在原来的配置文件上添加一下配置
  • 系统开发中我们常遇到要处理系统日志等信息的,在此我分享一篇 利用spring aop切面来异步添加日志的操作,其中用到了 队列和多线程,前面的博客有。 第一步:创建log实体,根据自己业务而定, package ...
  • spring aop 异步处理系统日志

    万次阅读 2016-06-14 11:49:41
    spring aop 异步处理系统日志
  • java —— 异步任务失败后处理

    千次阅读 2019-06-29 23:24:04
    场景: ...但是如果是异步操作,比如用户注册成功后,系统异步发送短信给用户,发短信的操作出问题了没有发出去,而且这个操作也不是用户主动操作了,所以可能会出现用户不知道你有这个操作,系统...
  • Spring Boot支持Java Util Logging、Log4J、Log4J2和LockBack作为日志框架,无论使用哪种日志框架,Spring Boot都为当前使用的日志框架的控制台及文件输出做好了配置。 默认使用LockBack日志框架。 使用...
  • java使用@Async注解,异步方法 当业务逻辑执行完成后,需要发送信息或者记录日志等。而发送信息或者记录日志的成功与否对主业务逻辑没有影响,这时可以使用异步的方法,以提高主业务逻辑的性能。 //异步发送信息 ...
  • https://www.cnblogs.com/yeyang/p/7944906.html 同步日志异步日志 https://blog.csdn.net/RyanDon/article/details/82589989 https://www.jianshu.com/p/5dcf4ece0de3 log4j2 依赖 spring-boot-starter-log4j2 ...
  • 在用户操作量较大的情况下,如果实时写入日志会导致资源被严重占用,用户长时间获取不到返回结果,影响用户体验,所以日志操作通常是在用户操作完后放入异步队列,等用户操作少的时间段再将日志写入数据库。...
  • 异步调用实现对比 java

    千次阅读 2014-07-06 22:13:17
    异步调用主要用于当前程序的执行不用等待调用方法执行结束就可以继续执行。用一个最简单的例子来说,当前的方法要调用一个发送短信的方法,但是发送短信的方法调用了外部的接口,这样就导致短信发送方法耗费的时间很...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 73,879
精华内容 29,551
关键字:

java异步写日志

java 订阅