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.File;
 import java.io.FileInputStream;
import java.io.FileInputStream;
 import java.io.FileOutputStream;
import java.io.FileOutputStream;
 import java.io.IOException;
import java.io.IOException;
 import java.io.InputStream;
import java.io.InputStream;
 import java.io.OutputStream;
import java.io.OutputStream;
 import java.util.Observable;
import java.util.Observable;
 import java.util.Properties;
import java.util.Properties;

 import org.apache.log4j.Logger;
import org.apache.log4j.Logger;

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


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


 {
{
 private static DemoConfigManager myInstance = new DemoConfigManager();
    private static DemoConfigManager myInstance = new DemoConfigManager();

 private final String myName = "ConfigManager";
    private final String myName = "ConfigManager";

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

 private File configFile = null;
    private File configFile = null;

 private Properties myProperties = new Properties();
    private Properties myProperties = new Properties();

 private boolean myIsRunning = false;
    private boolean myIsRunning = false;

 private Thread myThread = null;
    private Thread myThread = null;


 /** *//**
    /** *//**
 * Default constructor.
     * Default constructor.
 */
     */
 private DemoConfigManager()
    private DemoConfigManager()

 
     {
{
 try
        try

 
         {
{
 String myConfigFile = System.getProperty("RealTimeConfigFile");
            String myConfigFile = System.getProperty("RealTimeConfigFile");
 if (myConfigFile == null || "".equals(myConfigFile))
            if (myConfigFile == null || "".equals(myConfigFile))

 
             {
{
 myConfigFile = "conf/RealTimeConfig.conf";
                myConfigFile = "conf/RealTimeConfig.conf";
 }
            }
 configFile = FileResolver.loadFile(myConfigFile);
            configFile = FileResolver.loadFile(myConfigFile);
 InputStream is = new FileInputStream(configFile);
            InputStream is = new FileInputStream(configFile);
 myProperties.load(is);
            myProperties.load(is);
 is.close();
            is.close();
 }
        }
 catch (IOException ex)
        catch (IOException ex)

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


 /** *//**
    /** *//**
 * Return the name of this subsystem.
     * Return the name of this subsystem.
 */
     */
 public String getName()
    public String getName()

 
     {
{
 return myName;
        return myName;
 }
    }


 /** *//**
    /** *//**
 * Get the singleton instance of this class.
     * Get the singleton instance of this class.
 *
     * 
 * @return The singleton instance.
     * @return The singleton instance.
 */
     */
 public static DemoConfigManager getInstance()
    public static DemoConfigManager getInstance()

 
     {
{
 return myInstance;
        return myInstance;
 }
    }


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

 
     {
{
 InputStream is = (InputStream) new FileInputStream(configFile);
        InputStream is = (InputStream) new FileInputStream(configFile);
 Properties aFromFileProp = new Properties();
        Properties aFromFileProp = new Properties();
 aFromFileProp.load(is);
        aFromFileProp.load(is);

 // Check if the properties in file has been updated compared to the stored properties.
        // Check if the properties in file has been updated compared to the stored properties.
 if (!aFromFileProp.toString().equals(myProperties.toString()))
        if (!aFromFileProp.toString().equals(myProperties.toString()))

 
         {
{
 myProperties = aFromFileProp;
            myProperties = aFromFileProp;
 this.setChanged();
            this.setChanged();
 this.notifyObservers();
            this.notifyObservers();
 }
        }
 is.close();
        is.close();
 }
    }


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

 
     {
{
 while (myIsRunning)
        while (myIsRunning)

 
         {
{
 int interval = 30;
            int interval = 30;
 try
            try

 
             {
{
 interval = Integer.parseInt(myProperties.getProperty("ReadConfigInterval"));
                interval = Integer.parseInt(myProperties.getProperty("ReadConfigInterval"));
 }
            }
 catch (NumberFormatException ex)
            catch (NumberFormatException ex)

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

 try
            try

 
             {
{
 Thread.sleep(interval * 1000);
                Thread.sleep(interval * 1000);
 load();
                load();
 }
            }
 catch (IOException ex)
            catch (IOException ex)

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

 
             {
{
 
                
 }
            }
 }
        }
 }
    }


 /** *//**
    /** *//**
 * Save the configuration to file. Existing configuration data will be over
     * Save the configuration to file. Existing configuration data will be over
 * written.
     * written.
 *
     * 
 * @throws IOException
     * @throws IOException
 *             If unable to open and write to file.
     *             If unable to open and write to file.
 */
     */
 public synchronized void save() throws IOException
    public synchronized void save() throws IOException

 
     {
{
 OutputStream os = (OutputStream) new FileOutputStream(configFile);
        OutputStream os = (OutputStream) new FileOutputStream(configFile);
 myProperties.store(os, "RealTimeConfig");
        myProperties.store(os, "RealTimeConfig");
 os.close();
        os.close();
 }
    }


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

 
     {
{
 return myProperties.getProperty(theKey);
        return myProperties.getProperty(theKey);
 }
    }


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

 
     {
{
 myProperties.setProperty(theKey, theValue);
        myProperties.setProperty(theKey, theValue);
 }
    }


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

 
     {
{
 return myProperties;
        return myProperties;
 }
    }


 /** *//**
    /** *//**
 * Start the ConfigManager and read configuration from file. From now on the
     * Start the ConfigManager and read configuration from file. From now on the
 * configuration will be read from file at a configurable interval, default
     * configuration will be read from file at a configurable interval, default
 * 30 seconds.
     * 30 seconds.
 */
     */
 public synchronized void startup() throws StartupFailureException
    public synchronized void startup() throws StartupFailureException

 
     {
{
 if (myIsRunning)
        if (myIsRunning)

 
         {
{
 throw new StartupFailureException("Subsystem is already running!");
            throw new StartupFailureException("Subsystem is already running!");
 }
        }

 myIsRunning = true;
        myIsRunning = true;

 myThread = new Thread(this, this.getName());
        myThread = new Thread(this, this.getName());
 myThread.start();
        myThread.start();
 }
    }


 /** *//**
    /** *//**
 * Shuts down the ConfigManager.
     * Shuts down the ConfigManager.
 *
     * 
 * @param theGracefulShutdownMode
     * @param theGracefulShutdownMode
 *            <code>true</code> if shut down should be graceful,
     *            <code>true</code> if shut down should be graceful,
 *            <code>false</code> otherwise.
     *            <code>false</code> otherwise.
 */
     */
 public synchronized void shutdown(boolean theGracefulShutdownMode)
    public synchronized void shutdown(boolean theGracefulShutdownMode)
 throws ShutdownFailureException
            throws ShutdownFailureException

 
     {
{
 if (!this.isRunning())
        if (!this.isRunning())

 
         {
{
 throw new ShutdownFailureException("Subsystem is already stopped!");
            throw new ShutdownFailureException("Subsystem is already stopped!");
 }
        }

 myIsRunning = false;
        myIsRunning = false;
 try
        try

 
         {
{
 myThread.interrupt();
            myThread.interrupt();
 myThread.join(1 * 60 * 1000);
            myThread.join(1 * 60 * 1000);
 }
        }
 catch (InterruptedException ex)
        catch (InterruptedException ex)

 
         {
{
 }
        }
 catch (SecurityException ex)
        catch (SecurityException ex)

 
         {
{
 }
        }

 myThread = null;
        myThread = null;
 }
    }


 /** *//**
    /** *//**
 * Checks if the ConfigManager is alive.
     * Checks if the ConfigManager is alive.
 *
     * 
 * @return <code>true</code> if alive, otherwise <code>false</code>.
     * @return <code>true</code> if alive, otherwise <code>false</code>.
 */
     */
 public boolean isRunning()
    public boolean isRunning()

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

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