How to end Singleton-object queue if I use Spring

2019-07-24 00:16发布

I have an application, that use Spring.AOP library to apply proxy-object to log what methods of program do (I use xml-configuration). Before I used log4net to log messages with Spring.AOP(simplified class):

public class CommandLoggingAdvice : IMethodInterceptor
{
    // here I get an instance of log4net
    private ILog _Logger = null;
    protected ILog Logger
    {
        _Logger = LogManager.GetLogger("Logger1");            
    }

    public object Invoke(IMethodInvocation invocation)
    {
        Logger1.Info("Now we enter to method");            
        // here i call the method
        object returnValue = invocation.Proceed();
        Logger1.Info("Now we exit from method");
        return returnValue;
    }
}

But there were a problem: I needed to use a queue of messages, which should work in independent thread to distribute program load on several thread

Here is a new Spring.AOP class:

public class CommandLoggingAdvice : IMethodInterceptor
{
    private static ProducerConsumerClass LoggingQueue = ProducerConsumerClass.Instance;    
    public object Invoke(IMethodInvocation invocation)
    {
        LoggingQueue.AddTask("Now we enter to method");            
        // here I call the method
        object returnValue = invocation.Proceed();
        LoggingQueue.AddTask("Now we exit from method");
        return returnValue;
    }
}


/// <summary>
/// ProducerConsumerClass implements: 
/// - SingleTon-object, Producer/Consumer queue (queue is a FIFO BlockingCollection) - I need this class to process all messages, which come from  CommonLoggingAdvice class. The reason is that I need to do it in independent thread (.IsBackground = false) 
/// - This version of Singleton class is threadsafe
/// </summary> 
public sealed class ProducerConsumerClass : IDisposable
{
    // here Iget an instance of log4net
    private ILog _Logger = null;
    protected ILog Logger
    {
        _Logger = LogManager.GetLogger("Logger1");            
    }

    private BlockingCollection<string> tasks = new BlockingCollection<string>();

    private static volatile ProducerConsumerClass _instance;
    private static object locker = new object();        
    Thread worker;

    private ProducerConsumerClass()
    {
        worker = new Thread(Work);
        worker.Name = "Queue thread";
        worker.IsBackground = false;
        worker.Start();
    }

    public static ProducerConsumerClass Instance
    {
        get
        {
            if (_instance == null)       
            {
                lock (locker)
                {
                    if (_instance == null)
                    {
                        _instance = new ProducerConsumerClass();
                    }
                }
            }
            return _instance;
        }
    }

    public void AddTask(string task)
    {
        tasks.Add(task);           
    }
 // now this is unused method
 // I need to call this method somehow at the end of program, but cross-cutting concern doesn't allow to do it straightahead
    public void Dispose()
    {
        tasks.CompleteAdding();
        worker.Join();                        
        tasks.Dispose();
    }

    void Work()
    {
        while (true)
        {
            string task = null;
            if (!tasks.IsCompleted)
            {
                Thread.Sleep(1000);
                task = tasks.Take();
                Logger1.Info(worker.Name + " " + task );   
            }
            else
            {
                return;
            }              
        }
    }
}

So this class is always running (and so the "worker" thread); if "tasks" is empty, - tasks.Take() forces "worker" thread to pause until something will be added using tasks.Add(). But when all functions of program are ended and i need to exit from program - "tasks" is empty and "worker" is paused - so I can not exit from infinite cycle => program never ends.

As long as Spring.AOP classes are cross-cutting and they apply automatically, I don't know how to tell "worker" thread ( method Work() ) that it should be completed ( CompleteAdding() method , or Dispose() ).

Could you help me with this problem or tell any other ways to do what I need:

  1. cross-cutting concern with Spring.AOP for logging
  2. threadsafe implemenation of Singleton-class with queue(or Producer/consumer pattern) in independent thread, which live as long as lives application and a little more: until the queue is empty.

1条回答
ら.Afraid
2楼-- · 2019-07-24 00:36

You can use a independent thread to write your log in a queue. Using lock to solve your needs about write in your queue.

查看更多
登录 后发表回答