今天看Log4j包中的实现,其中的LogManager类就好像用的工厂模式,所有的方法和成员都是类方法和类成员。
用的时候也不实例化,直接使用静态方法。
可是我怎么知道这个LogManager加载后存在了多长时间,下次再用的时候里面的成员还是不是以前的成员。

解决方案 »

  1.   

    估计一直存在jvm里面吧“下次再用”,如果是同一个jvm的,当然还是原来的值
      

  2.   

    设计模式中的“工厂模式”不是接口回调的问题吗?
    你这个问题和工厂模式没什么关系吧,你可以用log4j中getProperty获得logmanager的属性试试
      

  3.   


       18   package org.apache.log4j;
       19   
       20   import org.apache.log4j.spi.LoggerRepository;
       21   import org.apache.log4j.spi.LoggerFactory;
       22   import org.apache.log4j.spi.RepositorySelector;
       23   import org.apache.log4j.spi.DefaultRepositorySelector;
       24   import org.apache.log4j.spi.RootLogger;
       25   import org.apache.log4j.spi.NOPLoggerRepository;
       26   import org.apache.log4j.helpers.Loader;
       27   import org.apache.log4j.helpers.OptionConverter;
       28   import org.apache.log4j.helpers.LogLog;
       29   
       30   import java.net.URL;
       31   import java.net.MalformedURLException;
       32   
       33   
       34   import java.util.Enumeration;
       35      45   public class LogManager {
       46   
       47     /**
       48      * @deprecated This variable is for internal use only. It will
       49      * become package protected in future versions.
       50      * */
       51     static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
       52     
       53     static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";  
       54      
       55     /**
       56      * @deprecated This variable is for internal use only. It will
       57      * become private in future versions.
       58      * */
       59     static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
       60   
       61     /**
       62      * @deprecated This variable is for internal use only. It will
       63      * become private in future versions.
       64      * */
       65     static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
       66   
       67     /**
       68     * @deprecated This variable is for internal use only. It will
       69     * become private in future versions.
       70     */
       71     public static final String DEFAULT_INIT_OVERRIDE_KEY = 
       72                                                    "log4j.defaultInitOverride";
       73   
       74   
       75     static private Object guard = null;
       76     static private RepositorySelector repositorySelector;
       77   
       78     static {
       79       // By default we use a DefaultRepositorySelector which always returns 'h'.
       80       Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
       81       repositorySelector = new DefaultRepositorySelector(h);
       82   
       83       /** Search for the properties file log4j.properties in the CLASSPATH.  */
       84       String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
       85           null);
       86   
       87       // if there is no default init override, then get the resource
       88       // specified by the user or the default config file.
       89       if(override == null || "false".equalsIgnoreCase(override)) {
       90   
       91         String configurationOptionStr = OptionConverter.getSystemProperty(
       92      DEFAULT_CONFIGURATION_KEY, 
       93      null);
       94   
       95         String configuratorClassName = OptionConverter.getSystemProperty(
       96                                                      CONFIGURATOR_CLASS_KEY, 
       97       null);
       98   
       99         URL url = null;
      100   
      101         // if the user has not specified the log4j.configuration
      102         // property, we search first for the file "log4j.xml" and then
      103         // "log4j.properties"
      104         if(configurationOptionStr == null) {
      105    url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
      106    if(url == null) {
      107      url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
      108    }
      109         } else {
      110    try {
      111      url = new URL(configurationOptionStr);
      112    } catch (MalformedURLException ex) {
      113      // so, resource is not a URL:
      114      // attempt to get the resource from the class path
      115      url = Loader.getResource(configurationOptionStr); 
      116    }
      117         }
      118         
      119         // If we have a non-null url, then delegate the rest of the
      120         // configuration to the OptionConverter.selectAndConfigure
      121         // method.
      122         if(url != null) {
      123        LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
      124           try {
      125               OptionConverter.selectAndConfigure(url, configuratorClassName,
      126       LogManager.getLoggerRepository());
      127           } catch (NoClassDefFoundError e) {
      128               LogLog.warn("Error during default initialization", e);
      129           }
      130         } else {
      131        LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
      132         }
      133       }  
      134     } 
      135   
      136     /**
      137        Sets <code>LoggerFactory</code> but only if the correct
      138        <em>guard</em> is passed as parameter.
      139        
      140        <p>Initally the guard is null.  If the guard is
      141        <code>null</code>, then invoking this method sets the logger
      142        factory and the guard. Following invocations will throw a {@link
      143        IllegalArgumentException}, unless the previously set
      144        <code>guard</code> is passed as the second parameter.
      145   
      146        <p>This allows a high-level component to set the {@link
      147        RepositorySelector} used by the <code>LogManager</code>.
      148        
      149        <p>For example, when tomcat starts it will be able to install its
      150        own repository selector. However, if and when Tomcat is embedded
      151        within JBoss, then JBoss will install its own repository selector
      152        and Tomcat will use the repository selector set by its container,
      153        JBoss.  */
      154     static
      155     public
      156     void setRepositorySelector(RepositorySelector selector, Object guard) 
      157                                                    throws IllegalArgumentException {
      158       if((LogManager.guard != null) && (LogManager.guard != guard)) {
      159         throw new IllegalArgumentException(
      160              "Attempted to reset the LoggerFactory without possessing the guard.");
      161       }
      162   
      163       if(selector == null) {
      164         throw new IllegalArgumentException("RepositorySelector must be non-null.");
      165       }
      166   
      167       LogManager.guard = guard;
      168       LogManager.repositorySelector = selector;
      169     }
      170   
      171     static
      172     public
      173     LoggerRepository getLoggerRepository() {
      174       if (repositorySelector == null) {
      175           repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
      176           guard = null;
      177           LogLog.error("LogMananger.repositorySelector was null likely due to error in class reloading, using NOPLoggerRepository.");
      178       }
      179       return repositorySelector.getLoggerRepository();
      180     }
      181   
      182     /**
      183        Retrieve the appropriate root logger.
      184      */
      185     public
      186     static 
      187     Logger getRootLogger() {
      188        // Delegate the actual manufacturing of the logger to the logger repository.
      189       return getLoggerRepository().getRootLogger();
      190     }
      191   
      192     /**
      193        Retrieve the appropriate {@link Logger} instance.  
      194     */
      195     public
      196     static 
      197     Logger getLogger(final String name) {
      198        // Delegate the actual manufacturing of the logger to the logger repository.
      199       return getLoggerRepository().getLogger(name);
      200     }
      201   
      202    /**
      203        Retrieve the appropriate {@link Logger} instance.  
      204     */
      205     public
      206     static 
      207     Logger getLogger(final Class clazz) {
      208        // Delegate the actual manufacturing of the logger to the logger repository.
      209       return getLoggerRepository().getLogger(clazz.getName());
      210     }
      211   
      212   
      213     /**
      214        Retrieve the appropriate {@link Logger} instance.  
      215     */
      216     public
      217     static 
      218     Logger getLogger(final String name, final LoggerFactory factory) {
      219        // Delegate the actual manufacturing of the logger to the logger repository.
      220       return getLoggerRepository().getLogger(name, factory);
      221     }  
      222   
      223     public
      224     static
      225     Logger exists(final String name) {
      226       return getLoggerRepository().exists(name);
      227     }
      228   
      229     public
      230     static
      231     Enumeration getCurrentLoggers() {
      232       return getLoggerRepository().getCurrentLoggers();
      233     }
      234   
      235     public
      236     static
      237     void shutdown() {
      238       getLoggerRepository().shutdown();
      239     }
      240   
      241     public
      242     static
      243     void resetConfiguration() {
      244       getLoggerRepository().resetConfiguration();
      245     }
      246   }
      

  4.   

    猜测:如果它所有的字段和方法都是静态的话,那么也就是说jvm中只有一个此类的实例就够了,jvm每次在用到log的时候都会查看一下是否已经加载了此类,如果已经加载了就直接用LogManager的Class对象调用相关的方法(应为都是静态的和实例无关,所以就不用生成实例了),如果没有就再从新加载一次。
    所以应该是只有一个LogManager的Class对象,LogManager的实例可能就不曾存在过
    纯属个人猜测  技术有限 说不太清楚
      

  5.   

    类的调用过程是
    读取class文件,载入MetaClass类
    初始化类静态Field,Method
    创建对象
    初始对象Field,Method为null,0,flase
    调用constructor
    依次调用Filed的constructor即时里不产生对象,也会创建MetaClass类,它的生存期就是静态方法的生存期你可以用xxx.Class,或者class.forname之类的方法获得MetaClass类。
      

  6.   

    再同一个jvm下,按理来说应该是这个范围内的都有效的,可是有二,三十个包都用到这样一个类,总是让我有点怀疑,不同的包中都用到这样的生成方法,其中有一个全局的Log层次结构,这样的东西一直会留在JVM中?如果这样的类很多的话,JVM就不好玩了吧。继续讨论,晚上或明天结
      

  7.   


    这样的类不至于多到JVM受不了,一般常见于Utility性质的类
    当然你设计得不好就另当别论了
      

  8.   

    建议读一下类载入机制的相关文章。
    在jvm中,同一个类是可以有多个副本的,只要它们不是由同一个类载入器(ClassLoader)载入的。
    至于已经载入的类何时释放的问题么,SUN的虚拟机是不会释放的,而其他的虚拟机有可能会释放,比如Oracle(BEA)的——只要类载入器被回收了就可以释放。