随笔-46  评论-64  文章-2  trackbacks-0
log4j 支持运行时修改日志的相关配置,看了一下他的source code, 用FileWatchdog这个类来做的,代码也很简单,通过循环在一定时间间隔读取配置文件,如果文件变更,调用一个doOnChange()方法。

如果自己要做一个支持运行时修改配置的系统可参考上面的做法。

下面是一段支持运行时修改配置的系统Prototype代码,和log4j的做法稍有不同,使用Observer模式,使其更加灵活。

如果某个类要在系统配置修改时得到通知,则这个类要实现Observer接口,然后调用ConfigManager.getInstance().addObserver(this);

在void update(Observable o, Object args)方法里处理相应的属性即可。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Observable;
import java.util.Properties;

import org.apache.log4j.Logger;

import cn.heapstack.realtimeconfig.exception.ShutdownFailureException;
import cn.heapstack.realtimeconfig.exception.StartupFailureException;
import cn.heapstack.realtimeconfig.util.FileResolver;

/**
 * <p>
 * This class holds all configuration for the system. The configuration parameters
 * are read from file at configurable interval. 
 * 
 * This class implements the Singleton pattern.
 * 
 * Because this class extends the <code>Observable</code> class, an
 * <code>Observer</code> may register and get notified when the configuration
 * has changed.
 * </p>
 *
 
*/

public final class DemoConfigManager extends Observable implements Runnable
{
    
private static DemoConfigManager myInstance = new DemoConfigManager();

    
private final String myName = "ConfigManager";

    
private static final Logger myLog = Logger.getLogger(DemoConfigManager.class);;

    
private File configFile = null;

    
private Properties myProperties = new Properties();

    
private boolean myIsRunning = false;

    
private Thread myThread = null;

    
/**
     * Default constructor.
     
*/

    
private DemoConfigManager()
    
{
        
try
        
{
            String myConfigFile 
= System.getProperty("RealTimeConfigFile");
            
if (myConfigFile == null || "".equals(myConfigFile))
            
{
                myConfigFile 
= "conf/RealTimeConfig.conf";
            }

            configFile 
= FileResolver.loadFile(myConfigFile);
            InputStream is 
= new FileInputStream(configFile);
            myProperties.load(is);
            is.close();
        }

        
catch (IOException ex)
        
{
            System.err.println(
"Error reading RealTimeConfig configuration file. Will now exit RealTimeConfig: " + ex);
            System.exit(
-1);
        }

    }


    
/**
     * Return the name of this subsystem.
     
*/

    
public String getName()
    
{
        
return myName;
    }


    
/**
     * Get the singleton instance of this class.
     * 
     * 
@return The singleton instance.
     
*/

    
public static DemoConfigManager getInstance()
    
{
        
return myInstance;
    }


    
/**
     * Loads the configuration from file.
     * 
     * If find the configuration file changed, notify the observers
     * 
     * 
@throws IOException
     *             If unable to open and read configuration file.
     
*/

    
private void load() throws IOException
    
{
        InputStream is 
= (InputStream) new FileInputStream(configFile);
        Properties aFromFileProp 
= new Properties();
        aFromFileProp.load(is);

        
// Check if the properties in file has been updated compared to the stored properties.
        if (!aFromFileProp.toString().equals(myProperties.toString()))
        
{
            myProperties 
= aFromFileProp;
            
this.setChanged();
            
this.notifyObservers();
        }

        is.close();
    }


    
/**
     * The run method of the ConfigManager thread. It will read the
     * configuration from file every 30 seconds.
     
*/

    
public void run()
    
{
        
while (myIsRunning)
        
{
            
int interval = 30;
            
try
            
{
                interval 
= Integer.parseInt(myProperties.getProperty("ReadConfigInterval"));
            }

            
catch (NumberFormatException ex)
            
{
                myLog.info(
                        
"Error reading ReadConfigInterval config parameter. Using default value("+interval+").");
            }


            
try
            
{
                Thread.sleep(interval 
* 1000);
                load();
            }

            
catch (IOException ex)
            
{
                myLog.info( 
"IO error while trying to load config file: "
                        
+ ex.getMessage());
            }

            
catch (InterruptedException ex)
            
{
                
            }

        }

    }


    
/**
     * Save the configuration to file. Existing configuration data will be over
     * written.
     * 
     * 
@throws IOException
     *             If unable to open and write to file.
     
*/

    
public synchronized void save() throws IOException
    
{
        OutputStream os 
= (OutputStream) new FileOutputStream(configFile);
        myProperties.store(os, 
"RealTimeConfig");
        os.close();
    }


    
/**
     * Get a configuration value of a specified parameter (key).
     * 
     * 
@param theKey
     *            The name of the parameter to fetch a value from.
     * 
     * 
@return The configuration value for the specified key.
     
*/

    
public synchronized String get(String theKey)
    
{
        
return myProperties.getProperty(theKey);
    }


    
/**
     * Set a configuration value of a specified parameter (key).
     * 
     * 
@param theKey
     *            The name of the parameter to set.
     * 
     * 
@param theValue
     *            The value of the parameter to set.
     
*/

    
public synchronized void set(String theKey, String theValue)
    
{
        myProperties.setProperty(theKey, theValue);
    }


    
/**
     * Get all parameters contained in the ConfigManager.
     * 
     * 
@return A Properties object containing all configuration parameters and
     *         their value.
     
*/

    
public synchronized Properties getProperties()
    
{
        
return myProperties;
    }


    
/**
     * Start the ConfigManager and read configuration from file. From now on the
     * configuration will be read from file at a configurable interval, default
     * 30 seconds.
     
*/

    
public synchronized void startup() throws StartupFailureException
    
{
        
if (myIsRunning)
        
{
            
throw new StartupFailureException("Subsystem is already running!");
        }


        myIsRunning 
= true;

        myThread 
= new Thread(thisthis.getName());
        myThread.start();
    }


    
/**
     * Shuts down the ConfigManager.
     * 
     * 
@param theGracefulShutdownMode
     *            <code>true</code> if shut down should be graceful,
     *            <code>false</code> otherwise.
     
*/

    
public synchronized void shutdown(boolean theGracefulShutdownMode)
            
throws ShutdownFailureException
    
{
        
if (!this.isRunning())
        
{
            
throw new ShutdownFailureException("Subsystem is already stopped!");
        }


        myIsRunning 
= false;
        
try
        
{
            myThread.interrupt();
            myThread.join(
1 * 60 * 1000);
        }

        
catch (InterruptedException ex)
        
{
        }

        
catch (SecurityException ex)
        
{
        }


        myThread 
= null;
    }


    
/**
     * Checks if the ConfigManager is alive.
     * 
     * 
@return <code>true</code> if alive, otherwise <code>false</code>.
     
*/

    
public boolean isRunning()
    
{
        
return (myThread != null && myThread.isAlive() && myIsRunning);
    }

}

posted on 2008-09-04 14:49 jht 阅读(1306) 评论(0)  编辑  收藏 所属分类: J2SE

只有注册用户登录后才能发表评论。


网站导航: