`

Decorator模式的应用

阅读更多

最近在对一个系统做性能优化!


现状分析:
该系统有三类线程:


A类-接收线程: 从mq中获取消息(消息字符数大约1千至3千个字符);该类线程可以启动多个,因为可以从多个mq队列获取消息;


B类-处理线程: 获取A类线程接收的消息并进行解析和逻辑处理,最后生成新的消息传递给C类线程,B类线程是单线程;


C类-发送线程: 将B类线程生成的新消息(新消息字符数大约2千至9千个字符),发送给多个mq队列,C类线程为多个线程;



A类线程调用A_Logger日志对象打印接收到的消息(有1+个A类线程共享A_Logger日志对象);

B类线程调用B_Logger日志对象打印处理过程中的日志以便跟踪处理流程(单个B线程会在处理过程中多次打印处理日志);

C类线程调用C_Logger日志对象打印B类线程处理后生成的消息(有1+个C类线程共享C_Logger对象);

//注释:这里的logger日志对象用的是log4j



分析:

  • 因为对一个logger对象进行调用的时候,logger是会被加锁的,所以多线程同时调用一个logger的时候,其实它们是串行执行的;
  • 打印日志这种事,完全跟当前的业务处理逻辑没有任何关系,所以可以考虑使用单独的线程去做这种事;



改造方案:

  • 为每一类Logger日志对象创建单独的线程,在线程里面负责真正的日志打印(因为日志对象不是很多,所以这样创建的线程也不会很多);
  • 将在程序中调用Logger对象打印日志的操作修改为把需要打印的日志内容传递给相应的日志打印线程来处理;
  • 尽量避免对程序中打印日志部分代码的修改;这个时候就能使用装饰者模式(Decorator)了;




Decorator定义:

动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.

package kpicomm;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import DBUtil.MethodTime;

/**
 * 异步日志打印组件!
 * 
 * 该类用作将日志操作从当前的业务线程中分离出来,交给单独的日志打印线程来操作;
 * 该类的实现依赖于slf4j;
 * 
 * 使用方法:
 * 1.调用静态的LoggerAsyn.getLogger获取日志组件;(初始调用会创建一个异步日志组件,并作为线程运行);
 * 2.像log4j,slf4j一样调用isDebugEnabled,debug等方法;
 * 3.LoggerAsyn.removeLogger删除对应日志组件,并且停止线程;
 * 
 * @author LostHu
 *
 */
public class LoggerAsyn extends LoggerAsynAdapter implements Runnable{
	
	static private Map<Logger ,Logger >  loggerMap = new HashMap<Logger, Logger>();

	private MethodTime methodTime = new MethodTime();
	/**
	 * 根据日志组件名称获取异步日志打印组件
	 * @param loggerName 日志组件名称
	 * @return
	 */
	public static Logger  getLogger(String loggerName){
		Logger logger = LoggerFactory.getLogger(loggerName);
		return getLogger(logger);
	}
	
	/**
	 * 根据slf4j日志组件对象获取异步日志打印组件
	 * @param logger slf4j日志组件对象
	 * @return
	 */
	public static Logger  getLogger(Logger logger){
		Logger loggerReturn = null;
		synchronized (loggerMap) {
			loggerReturn = loggerMap.get(logger);
			if (loggerReturn == null){
				loggerReturn = new	LoggerAsyn(logger);
				loggerMap.put(logger, loggerReturn);
				new Thread((LoggerAsyn)loggerReturn).start();
			}
		}
		return loggerReturn;
	}
	
	/**
	 * 删除日志组件名称对应的异步日志打印组件,并停止该日志打印线程
	 * @param loggerName 日志组件名称
	 * @return
	 */
	public static boolean removeLogger(String loggerName){
		Logger logger = LoggerFactory.getLogger(loggerName);
		return removeLogger(logger);
	}
	
	/**
	 * 删除slf4j日志组件对象对应的异步日志打印组件,并停止该日志打印线程
	 * @param loggerName slf4j日志组件对象
	 * @return
	 */
	public static boolean removeLogger(Logger logger){
		if (logger == null) return true;
		Logger loggerReturn = null;
		synchronized (loggerMap) {
			loggerReturn = loggerMap.get(logger);
			if (loggerReturn != null){
				((LoggerAsyn)loggerReturn).isRunning = false;
			}
			loggerMap.remove(logger);
		}
		return true;
	}
	
	/**
	 * 真实被委托打印的日志对象
	 */
	private Logger realLogger ;
	
	/**
	 * 日志组件线程是否运行
	 */
	private volatile boolean isRunning = true;
	
	public Logger getRealLogger() {
		return realLogger;
	}
	
	/**
	 * 私有的构造方法,只有在静态的getLogger才被调用;
	 * 传入的日志打印组件为null的时候,会默认一个名字为LoggerAsyn的日志对象(避免这种情况)
	 * @param logger 真实的日志打印组件;
	 */
	private LoggerAsyn(Logger logger) {
		super();
		this.realLogger = logger;
		if (this.realLogger==null){
			this.realLogger = LoggerFactory.getLogger("LoggerAsyn");
		}
	}
	
	LinkedBlockingQueue<LogEvent>  clq = new LinkedBlockingQueue<LogEvent>();
	
	LinkedBlockingQueue<LogEvent> getClq() {
		return clq;
	}

	public void run(){
		Thread.currentThread().setName(getRealLogger().getName());
		LogEvent logEvent = null;
		
		while(isRunning){
			try {
				logEvent = getClq().take();
				if (isRunning){
					if (logEvent!=null){
						methodTime.start(getRealLogger().getName());
						switch (logEvent.getLog_level()) {
						case LoggerAsyn.DEBUG_LEVEL:
							getRealLogger().debug(logEvent.getLogString());
							break;
						case LoggerAsyn.INFO_LEVEL:
							getRealLogger().info(logEvent.getLogString());
							break;
						case LoggerAsyn.WARN_LEVEL:
							getRealLogger().warn(logEvent.getLogString());
							break;	
						case LoggerAsyn.ERROR_LEVEL:
							getRealLogger().error(logEvent.getLogString());
							break;	
						default:
							getRealLogger().info(logEvent.getLogString());
							break;
						}
						methodTime.end(getRealLogger().getName());
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 日志打印事件对象 
	 * @author LostHu
	 *
	 */
	class LogEvent{
		/**
		 * 日志打印的级别
		 */
		int log_level;
		/**
		 * 日志打印的内容
		 */
		String logString;
		
		public LogEvent(int log_level, String logString) {
			super();
			this.log_level = log_level;
			this.logString = logString;
		}
		public int getLog_level() {
			return log_level;
		}
		public void setLog_level(int log_level) {
			this.log_level = log_level;
		}
		public String getLogString() {
			return logString;
		}
		public void setLogString(String logString) {
			this.logString = logString;
		}
	}

	
	@Override
	public void debug(String arg0) {
		LogEvent le = new LogEvent(LoggerAsyn.DEBUG_LEVEL,arg0);
		clq.add(le);
	}
	
	@Override
	public void info(String arg0) {
		LogEvent le = new LogEvent(LoggerAsyn.INFO_LEVEL,arg0);
		clq.add(le);
	}
	
	@Override
	public void warn(String arg0) {
		LogEvent le = new LogEvent(LoggerAsyn.WARN_LEVEL,arg0);
		clq.add(le);
	}
	
	@Override
	public void error(String arg0) {
		LogEvent le = new LogEvent(LoggerAsyn.ERROR_LEVEL,arg0);
		clq.add(le);
	}

	@Override
	public boolean isDebugEnabled() {
		return getRealLogger().isDebugEnabled();
	}

	@Override
	public boolean isInfoEnabled() {
		return getRealLogger().isInfoEnabled();
	}
	
	@Override
	public boolean isWarnEnabled() {
		return getRealLogger().isWarnEnabled();
	}

	@Override
	public boolean isErrorEnabled() {
		return getRealLogger().isErrorEnabled();
	}
	
}

 

代码解释:

LoggerAsyn是实现org.slf4j.Logger接口,是对真实Logger对象的装饰者(因为真正的日志打印还是委托给真实的Logger对象)

 

使用LoggerAsyn对象去改造程序:

 

 改造前代码:

 

private static Logger log = LoggerFactory.getLogger("xxxx");

 

 改造后代码

 

private static Logger log_proc = LoggerAsyn.getLogger("xxxx");

 

非常简单,改动量非常非常小!

 

源代码请见附件!

 

分享到:
评论

相关推荐

    设计模式之 Decorator模式和代码实现

    总的来说,Decorator模式在奇幻RPG游戏中的应用展示了如何通过组合而非继承来动态扩展对象的功能。这种模式在保持代码可读性和可维护性的同时,提供了高度的灵活性,使得游戏中的武器能够根据玩家的选择拥有多种可能...

    Java类库中Decorator模式的应用研究.pdf

    ### Java类库中Decorator模式的应用研究 #### 一、引言 随着软件开发技术的不断发展,设计模式在软件工程中的重要性日益凸显。设计模式能够帮助开发者构建出具有良好结构、高度可扩展性和易于维护的软件系统。其中...

    java Decorator设计模式应用

    java Decorator设计模式应用,可以简单了解它,初学者入。

    C++ Decorator模式

    Decorator模式是设计模式中的一种结构型模式,它允许在运行时动态地给对象添加新的行为或职责,而不会破坏封装性。...通过熟练掌握和应用Decorator模式,开发者能够创建出更加灵活、可扩展的软件系统。

    Decorator模式

    应用Decorator模式的一个经典例子是在软件开发中处理用户界面元素。例如,假设我们有一个基础的`Button`类,用于创建简单的按钮。然后,我们可能希望为按钮添加不同的特性,如阴影、边框或动画。我们可以创建多个...

    C#设计模式之Decorator 装饰模式

    在.NET框架中,Stream类就是一个很好的装饰模式应用例子,例如GZipStream和DeflateStream通过装饰基础Stream对象实现了数据的压缩。 总结来说,学习C#中的装饰模式将帮助你更好地理解和利用面向对象的设计原则,如...

    设计模式的一些参考资料

    Decorator模式则用于动态地给对象添加额外的功能,而不改变其原有结构,Java的IO库就是一个很好的Decorator模式应用案例。此外,书中还详细讨论了其他模式的使用场景和注意事项,有助于读者深入理解和掌握这些模式。...

    2022年Decorator模式中遭遇继承与聚合Java教程.docx

    在实际应用中,Decorator模式常用于GUI组件(如添加边框、改变颜色等)、日志记录(添加不同级别的日志输出)、数据库连接池(动态增加连接管理策略)等场景。它通过避免过多的子类来保持类的灵活性和可维护性,同时...

    设计模式之Decorator

    我们先来看一下给定的文件名称列表,这些文件代表了Decorator模式的一个具体应用实例: 1. `Client.java` - 客户端代码,用于创建和使用装饰器对象。 2. `TicketDecorator.java` - 这是装饰器的基类,定义了装饰器...

    大话西游之设计模式_从猴王学艺看Decorator 配套代码

    在配套代码中,我们可以看到如何实际应用Decorator模式。首先,有一个基础的`Monkey`类,代表未经装饰的猴王,它可能有基本的行为如`learnSkill`。然后,创建一系列装饰类,如`FlyDecorator`、`BreatheFireDecorator...

    装饰器(Decorator)模式

    装饰器(Decorator)模式 装饰器(Decorator)模式是一种典型的结构型模式,主要用意是动态地为对象添加一些额外...装饰器模式是一种非常实用的设计模式,在软件设计中可以广泛地应用于解决类库膨胀和维护的困难问题。

    IO流所涉及到的Decorator设计模式

    理解Decorator模式在IO流中的应用对于开发人员来说至关重要,因为它可以帮助我们更有效地利用Java的IO功能。例如,当我们需要提高文件读取速度时,可以使用BufferedInputStream;如果要确保数据传输的完整性,...

    装饰者模式——Decorator

    装饰者模式(Decorator)是一种设计模式,用于在运行时动态地给对象添加额外的责任或功能。它是结构型设计模式的一种,能将行为的增加与对象的创建分离,使得我们可以独立地扩展对象的功能。 在Java或其他面向对象...

    [结构型模式] head first 设计模式之装饰者模式(decorator)

    【标题】:“装饰者模式(decorator)在Head First设计模式中的详解” ...通过阅读`beverage.h`文件中的类定义,我们可以深入理解这个模式的实现细节,并在实际项目中应用这一模式来优化代码结构和提高可扩展性。

    设计模式 t07Decorator

    设计模式是软件工程中的一种最佳实践,用于解决常见的设计问题并提供可重用的解决方案。在给定的“设计模式 t07Decorator”主题中,我们聚焦于...通过理解和应用装饰者模式,我们可以构建更易于维护和扩展的代码结构。

    Decorator装饰者模式

    装饰者模式是一种面向对象的设计模式,它允许在运行时向对象添加新的行为或属性,而无需...通过学习Head First的装饰者模式,开发者可以更好地掌握这一模式,并将其应用到实际项目中,提升代码的可维护性和可扩展性。

    spring如何实现注入多个数据源[归类].pdf

    2. **Decorator模式应用** 为了能够在运行时动态切换数据源,我们可以创建一个名为`MultiDataSource`的类,该类将作为数据源的Decorator。`MultiDataSource`将持有真实数据源的引用,并根据业务逻辑决定使用哪个...

    Java精华版 chm Java API、嵌套类和内部类、与时间有关的类Date,DateFormat,Calendar、文件与流、Java变量类型间的相互转换、Java与Web、用连接池提高Servlet访问数据库的效率、Java扩展、应用服务器的集群策略及Java EE 5.0、Java IO 包中的Decorator模式等

    DateFormat,Calendar、文件与流、Java变量类型间的相互转换、Java与Web、用连接池提高Servlet访问数据库的效率、Java扩展、应用服务器的集群策略及Java EE 5.0、Java IO 包中的Decorator模式等。

Global site tag (gtag.js) - Google Analytics