- 浏览: 951971 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
java中volatile关键字的含义:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html
Java transient关键字使用小记:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
Log4j初始化详解:http://donald-draper.iteye.com/blog/2332385
Log4j日志输出详解 :http://donald-draper.iteye.com/blog/2332395
slf4j + Log4j的使用:http://donald-draper.iteye.com/blog/2332407
上一篇简单学习了Log4j的使用,今天来看一下,日志初始化,
我们就从下面这一句来看:
查看Logger
来看LogManager的getLogger方法
//LogManager
//NOPLoggerRepository
//NOPLogger
而Logger继承Category
//Category
//Level
//Priority
我们在回到LogManager加载log4j属性文件,关键在这一句
这个LoggerRepository实际为NOPLoggerRepository
来看log4j.properties属性文件解析
//PropertyConfigurator
//配置RootCategory,rootLogger,appenders
来看 OptionConverter.findAndSubst
//返回key对应的属性
//NOPLoggerRepository,获取rootLogger
//PropertyConfigurator
//根据appenderName解析Appender
//OptionConverter.instantiateByKey
//PropertyConfigurator
// protected Hashtable registry;HashTable<String,Appender>
//将Appender放入registry
下面我们来看看logger.addAppender,都做了些什么
//AppenderAttachableImpl
总结:
从以上我们可以看出:log4j,通过LogManager的static语句块,加载配置log4j.properties,由OptionConverter去加载log4j.properties,并委托给PropertyConfigurator,去配置RootLogger,根据RootLogger获取Appender,然后根据属性文件初始化Appender,并添加到RootLogger的appender集合中。
Java transient关键字使用小记:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html
Log4j初始化详解:http://donald-draper.iteye.com/blog/2332385
Log4j日志输出详解 :http://donald-draper.iteye.com/blog/2332395
slf4j + Log4j的使用:http://donald-draper.iteye.com/blog/2332407
上一篇简单学习了Log4j的使用,今天来看一下,日志初始化,
我们就从下面这一句来看:
private static Logger log = Logger.getLogger(testLog4j.class);
查看Logger
public class Logger extends Category { protected Logger(String name) { super(name); } //获取Logger public static Logger getLogger(String name) { return LogManager.getLogger(name); } public static Logger getLogger(Class clazz) { return LogManager.getLogger(clazz.getName()); } static { FQCN = (org.apache.log4j.Logger.class).getName(); } }
来看LogManager的getLogger方法
//LogManager
public class LogManager { public static Logger getLogger(String name) { return getLoggerRepository().getLogger(name); } //获取本机LoggerRepository public static LoggerRepository getLoggerRepository() { if(repositorySelector == null) { repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository()); guard = null; Exception ex = new IllegalStateException("Class invariant violation"); String msg = "log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload."; if(isLikelySafeScenario(ex)) LogLog.debug(msg, ex); else LogLog.error(msg, ex); } return repositorySelector.getLoggerRepository(); } public static final String DEFAULT_CONFIGURATION_FILE = "log4j.properties"; static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml"; public static final String DEFAULT_CONFIGURATION_KEY = "log4j.configuration"; public static final String CONFIGURATOR_CLASS_KEY = "log4j.configuratorClass"; public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride"; private static Object guard = null; private static RepositorySelector repositorySelector; //加载log4j配置文件,先加载log4j.xml,如果log4j.xml不存在, //则加载log4j.properties文件 static { Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG)); repositorySelector = new DefaultRepositorySelector(h); String override = OptionConverter.getSystemProperty("log4j.defaultInitOverride", null); if(override == null || "false".equalsIgnoreCase(override)) { String configurationOptionStr = OptionConverter.getSystemProperty("log4j.configuration", null); String configuratorClassName = OptionConverter.getSystemProperty("log4j.configuratorClass", null); URL url = null; if(configurationOptionStr == null) { url = Loader.getResource("log4j.xml"); if(url == null) url = Loader.getResource("log4j.properties"); } else { try { url = new URL(configurationOptionStr); } catch(MalformedURLException ex) { url = Loader.getResource(configurationOptionStr); } } if(url != null) { LogLog.debug("Using URL [" + url + "] for automatic log4j configuration."); try { OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository()); } } } } }
//DefaultRepositorySelector public class DefaultRepositorySelector implements RepositorySelector { public DefaultRepositorySelector(LoggerRepository repository) { this.repository = repository; } public LoggerRepository getLoggerRepository() { return repository; } final LoggerRepository repository; }
//NOPLoggerRepository
public final class NOPLoggerRepository implements LoggerRepository { //从这里看,Logger实际上为NOPLogger public Logger getLogger(String name) { return new NOPLogger(this, name); } }
//NOPLogger
public final class NOPLogger extends Logger { public NOPLogger(NOPLoggerRepository repo, String name) { super(name); repository = repo; level = Level.OFF; parent = this; } }
而Logger继承Category
public class Logger extends Category { protected Logger(String name) { super(name); } }
//Category
public class Category implements AppenderAttachable { protected Category(String name) { additive = true; this.name = name; } protected String name; //volatile protected volatile Level level; protected volatile Category parent; private static final String FQCN; protected ResourceBundle resourceBundle; protected LoggerRepository repository; AppenderAttachableImpl aai; protected boolean additive; static { FQCN = (org.apache.log4j.Category.class).getName(); } }
//Level
public class Level extends Priority implements Serializable { protected Level(int level, String levelStr, int syslogEquivalent) { super(level, levelStr, syslogEquivalent); } public static final int TRACE_INT = 5000; public static final Level OFF = new Level(2147483647, "OFF", 0); public static final Level FATAL = new Level(50000, "FATAL", 0); public static final Level ERROR = new Level(40000, "ERROR", 3); public static final Level WARN = new Level(30000, "WARN", 4); public static final Level INFO = new Level(20000, "INFO", 6); public static final Level DEBUG = new Level(10000, "DEBUG", 7); public static final Level TRACE = new Level(5000, "TRACE", 7); public static final Level ALL = new Level(-2147483648, "ALL", 7); static final long serialVersionUID = 3491141966387921974L; }
//Priority
public class Priority { protected Priority() { level = 10000; levelStr = "DEBUG"; syslogEquivalent = 7; } protected Priority(int level, String levelStr, int syslogEquivalent) { this.level = level; this.levelStr = levelStr; this.syslogEquivalent = syslogEquivalent; } //比较日志级别 public boolean isGreaterOrEqual(Priority r) { return level >= r.level; } transient int level; transient String levelStr; transient int syslogEquivalent; public static final int OFF_INT = 2147483647; public static final int FATAL_INT = 50000; public static final int ERROR_INT = 40000; public static final int WARN_INT = 30000; public static final int INFO_INT = 20000; public static final int DEBUG_INT = 10000; public static final int ALL_INT = -2147483648; public static final Priority FATAL = new Level(50000, "FATAL", 0); public static final Priority ERROR = new Level(40000, "ERROR", 3); public static final Priority WARN = new Level(30000, "WARN", 4); public static final Priority INFO = new Level(20000, "INFO", 6); public static final Priority DEBUG = new Level(10000, "DEBUG", 7); }
我们在回到LogManager加载log4j属性文件,关键在这一句
OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository());
这个LoggerRepository实际为NOPLoggerRepository
public class OptionConverter { public static void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) { Configurator configurator = null; String filename = url.getFile(); if(clazz == null && filename != null && filename.endsWith(".xml")) clazz = "org.apache.log4j.xml.DOMConfigurator"; //XML配置解析 if(clazz != null) { LogLog.debug("Preferred configurator class: " + clazz); configurator = (Configurator)instantiateByClassName(clazz, org.apache.log4j.spi.Configurator.class, null); } else { //java属性文件解析log4j.properties configurator = new PropertyConfigurator(); } //配置NOPLoggerRepository configurator.doConfigure(url, hierarchy); } static String DELIM_START = "${"; static char DELIM_STOP = '}'; static int DELIM_START_LEN = 2; static int DELIM_STOP_LEN = 1; } }
来看log4j.properties属性文件解析
//PropertyConfigurator
public class PropertyConfigurator implements Configurator { protected Hashtable registry; private LoggerRepository repository; protected LoggerFactory loggerFactory; static final String CATEGORY_PREFIX = "log4j.category."; static final String LOGGER_PREFIX = "log4j.logger."; static final String FACTORY_PREFIX = "log4j.factory"; static final String ADDITIVITY_PREFIX = "log4j.additivity."; static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory"; static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger"; static final String APPENDER_PREFIX = "log4j.appender."; static final String RENDERER_PREFIX = "log4j.renderer."; static final String THRESHOLD_PREFIX = "log4j.threshold"; private static final String THROWABLE_RENDERER_PREFIX = "log4j.throwableRenderer"; private static final String LOGGER_REF = "logger-ref"; private static final String ROOT_REF = "root-ref"; private static final String APPENDER_REF_TAG = "appender-ref"; public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory"; private static final String RESET_KEY = "log4j.reset"; private static final String INTERNAL_ROOT_NAME = "root"; public PropertyConfigurator() { registry = new Hashtable(11); loggerFactory = new DefaultCategoryFactory(); } //加载URL文件到Properties public void doConfigure(URL configURL, LoggerRepository hierarchy) { Properties props; InputStream istream; props = new Properties(); istream = null; URLConnection uConn = null; URLConnection uConn = configURL.openConnection(); uConn.setUseCaches(false); istream = uConn.getInputStream(); props.load(istream); //加载URL文件到Properties doConfigure(props, hierarchy); } //根据properties文件配置NOPLoggerRepository public void doConfigure(Properties properties, LoggerRepository hierarchy) { repository = hierarchy; String value = properties.getProperty("log4j.debug"); if(value == null) { value = properties.getProperty("log4j.configDebug"); if(value != null) LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead."); } if(value != null) LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true)); String reset = properties.getProperty("log4j.reset"); if(reset != null && OptionConverter.toBoolean(reset, false)) hierarchy.resetConfiguration(); String thresholdStr = OptionConverter.findAndSubst("log4j.threshold", properties); if(thresholdStr != null) { hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr, Level.ALL)); LogLog.debug("Hierarchy threshold set to [" + hierarchy.getThreshold() + "]."); } //配置RootCategory,rootLogger,appenders configureRootCategory(properties, hierarchy); configureLoggerFactory(properties); parseCatsAndRenderers(properties, hierarchy); LogLog.debug("Finished configuring."); registry.clear(); } }
//配置RootCategory,rootLogger,appenders
void configureRootCategory(Properties props, LoggerRepository hierarchy) { String effectiveFrefix = "log4j.rootLogger"; String value = OptionConverter.findAndSubst("log4j.rootLogger", props); if(value == null) { LogLog.debug("Could not find root logger information. Is this OK?"); } else { Logger root = hierarchy.getRootLogger(); synchronized(root) { parseCategory(props, root, effectiveFrefix, "root", value); } } }
来看 OptionConverter.findAndSubst
//返回key对应的属性
public static String findAndSubst(String key, Properties props) { String value; value = props.getProperty(key); }
//NOPLoggerRepository,获取rootLogger
public Logger getRootLogger() { return new NOPLogger(this, "root"); }
//PropertyConfigurator
void parseCategory(Properties props, Logger logger, String optionKey, String loggerName, String value) { StringTokenizer st = new StringTokenizer(value, ","); if(!value.startsWith(",") && !value.equals("")) { if(!st.hasMoreTokens()) return; //获取rootLogger,日志级别 String levelStr = st.nextToken(); if("inherited".equalsIgnoreCase(levelStr) || "null".equalsIgnoreCase(levelStr)) { if(loggerName.equals("root")) LogLog.warn("The root logger cannot be set to null."); else logger.setLevel(null); } else { //设置rootLogger,日志级别 logger.setLevel(OptionConverter.toLevel(levelStr, Level.DEBUG)); } LogLog.debug("Category " + loggerName + " set to " + logger.getLevel()); } //移除Appenders logger.removeAllAppenders(); do { if(!st.hasMoreTokens()) break; String appenderName = st.nextToken().trim(); if(appenderName != null && !appenderName.equals(",")) { LogLog.debug("Parsing appender named \"" + appenderName + "\"."); //根据appenderName解析Appender Appender appender = parseAppender(props, appenderName); if(appender != null) //添加appender logger.addAppender(appender); } } while(true); }
//根据appenderName解析Appender
Appender parseAppender(Properties props, String appenderName) { Appender appender = registryGet(appenderName); if(appender != null) { LogLog.debug("Appender \"" + appenderName + "\" was already parsed."); return appender; } //log4j.appender的前缀 String prefix = "log4j.appender." + appenderName; //log4j.appender.appenderName.layout String layoutPrefix = prefix + ".layout"; //加载Appender,Class, //log4j.appender.D = org.apache.log4j.DailyRollingFileAppender appender = (Appender)OptionConverter.instantiateByKey(props, prefix, org.apache.log4j.Appender.class, null); appender.setName(appenderName); if(appender instanceof OptionHandler) { if(appender.requiresLayout()) { //加载Layout,class, //log4j.appender.D.layout = org.apache.log4j.PatternLayout Layout layout = (Layout)OptionConverter.instantiateByKey(props, layoutPrefix, org.apache.log4j.Layout.class, null); if(layout != null) { appender.setLayout(layout); LogLog.debug("Parsing layout options for \"" + appenderName + "\"."); //设置layout的属性 PropertySetter.setProperties(layout, props, layoutPrefix + "."); LogLog.debug("End of parsing for \"" + appenderName + "\"."); } } String errorHandlerPrefix = prefix + ".errorhandler"; String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props); if(errorHandlerClass != null) { ErrorHandler eh = (ErrorHandler)OptionConverter.instantiateByKey(props, errorHandlerPrefix, org.apache.log4j.spi.ErrorHandler.class, null); if(eh != null) { appender.setErrorHandler(eh); LogLog.debug("Parsing errorhandler options for \"" + appenderName + "\"."); parseErrorHandler(eh, errorHandlerPrefix, props, repository); Properties edited = new Properties(); String keys[] = { errorHandlerPrefix + "." + "root-ref", errorHandlerPrefix + "." + "logger-ref", errorHandlerPrefix + "." + "appender-ref" }; Iterator iter = props.entrySet().iterator(); do { if(!iter.hasNext()) break; java.util.Map.Entry entry = (java.util.Map.Entry)iter.next(); int i; for(i = 0; i < keys.length && !keys[i].equals(entry.getKey()); i++); if(i == keys.length) edited.put(entry.getKey(), entry.getValue()); } while(true); PropertySetter.setProperties(eh, edited, errorHandlerPrefix + "."); LogLog.debug("End of errorhandler parsing for \"" + appenderName + "\"."); } } //设置Appender属性 PropertySetter.setProperties(appender, props, prefix + "."); LogLog.debug("Parsed \"" + appenderName + "\" options."); } parseAppenderFilters(props, appenderName, appender); //将Appender放入registry registryPut(appender); return appender; }
//OptionConverter.instantiateByKey
public static Object instantiateByKey(Properties props, String key, Class superClass, Object defaultValue) { String className = findAndSubst(key, props); if(className == null) { LogLog.error("Could not find value for key " + key); return defaultValue; } else { return instantiateByClassName(className.trim(), superClass, defaultValue); } }
//PropertyConfigurator
// protected Hashtable registry;HashTable<String,Appender>
//将Appender放入registry
void registryPut(Appender appender) { registry.put(appender.getName(), appender); }
下面我们来看看logger.addAppender,都做了些什么
public class Category implements AppenderAttachable { //添加Appender public synchronized void addAppender(Appender newAppender) { if(aai == null) aai = new AppenderAttachableImpl(); aai.addAppender(newAppender); //通知repository,添加Appender事件 repository.fireAddAppenderEvent(this, newAppender); } //移除AllAppenders public synchronized void removeAllAppenders() { if(aai != null) { Vector appenders = new Vector(); for(Enumeration iter = aai.getAllAppenders(); iter != null && iter.hasMoreElements(); appenders.add(iter.nextElement())); aai.removeAllAppenders(); for(Enumeration iter = appenders.elements(); iter.hasMoreElements(); fireRemoveAppenderEvent((Appender)iter.nextElement())); aai = null; } } }
//AppenderAttachableImpl
public class AppenderAttachableImpl implements AppenderAttachable { //添加Appender public void addAppender(Appender newAppender) { if(newAppender == null) return; if(appenderList == null) appenderList = new Vector(1); if(!appenderList.contains(newAppender)) appenderList.addElement(newAppender); } //Vector<Appender> protected Vector appenderList; }
总结:
从以上我们可以看出:log4j,通过LogManager的static语句块,加载配置log4j.properties,由OptionConverter去加载log4j.properties,并委托给PropertyConfigurator,去配置RootLogger,根据RootLogger获取Appender,然后根据属性文件初始化Appender,并添加到RootLogger的appender集合中。
发表评论
-
一次服务器事故处理过程及教训
2017-02-24 18:50 1108java虚拟机内存查看相关 ... -
slf4j + Logback使用
2016-10-23 19:44 1306使用logback轻松管理日志: http://blog.cs ... -
slf4j + Logback详解
2016-10-23 19:41 1261Log4j初始化详解:http://donald-draper ... -
slf4j + Log4j 详解
2016-10-23 19:40 1671Log4j初始化详解:http://donald-draper ... -
sfl4j与log4j使用
2016-10-23 11:24 2366slf4j-api、slf4j-log4j12以及log4j之 ... -
Log4j日志输出详解
2016-10-23 00:46 2774Log4j初始化详解:http://donald-draper ... -
log4j的使用
2016-10-22 11:56 578Log4j使用教程:http://www.codeceo.co ... -
Spring集成log4j,日志初始化过程详解
2016-06-22 17:41 7719以前研究过slf4j-log4j的使用,但具体初始化过程不是很 ...
相关推荐
本文实例讲述了Android4.X中SIM卡信息初始化过程详解。分享给大家供大家参考,具体如下: Phone 对象初始化的过程中,会加载SIM卡的部分数据信息,这些信息会保存在IccRecords 和 AdnRecordCache 中。SIM卡的数据...
8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...
蓝牙协议栈下按键的使用 SDK15 蓝牙5.0笔记12:(蓝牙工程搭建篇)蓝牙协议栈初始化详解 SDK15 蓝牙5.0笔记13:(蓝牙工程搭建篇)蓝牙5.0GAP与GATT详解 SDK15 蓝牙5.0笔记14:(蓝牙工程搭建篇)蓝牙广播初始化与...
不管是我参与的别人已经搭建好的项目还是我自己主导的项目,日志框架基本都换成了logback,总结一下,logback大约有以下的一些优点:内核重写、测试充分、初始化内存加载更小,这一切让logback性能和log4j相比有诸多...
Springboot-注解-通用操作日志组件此组件解决的问题是: 「谁」在「什么时间」对「什么」做了「什么事」本组件目前针对 Spring-boot 做了 Autoconfig,如果是 SpringMVC,也可自己在 xml 初始化 beanChange Log版本...
在oracle的初始化参数中,与归档日志目录有关的有:log_archive_dest, log_archive_dest_n和standby_archive_dest, 那么这三个参数的相互关系如何呢,下面就通过试验进行详细讲解。实验环境为oracle11g。
8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...
8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...
8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...
onLaunch—-当小程序初始化完成时,会触发 onLaunch(全局只触发一次) onShow —-当小程序启动,或从后台进入前台显示,会触发 onShow onHide —-当小程序从前台进入后台,会触发 onHide onError —-当小程序发生...
二:Wifi模块的初始化::在SystemServer启动的时候,会生成一个ConnectivityService的实例,try{Log.i(TAG,"StartingConnectivityService.");ServiceManager.addService(Context.CONNECTIVITY_SERVICE,...
Erase 语句 重新初始化固定数组的元素并重新分配动态数组的存储空间。 Err 对象 含有关于运行时错误的信息。 Eval 函数 计算并返回表达式的值。 Execute 方法 根据指定的字符串,执行正则表达式的搜索。 Execute...
JSON.stringify() 方法能将一个 JavaScript 对象或值转换成一个...//初始化一个 user 对象 const user = { name : Prateek Singh, age : 26 } console.log(user); // 结果 // [object Object] 哦!console.log
1.定义变量,但是没有初始化时,如var a; 2.调用某个函数时,实参个数小于形参个数时,未实参化的形参在函数调用过程中的值是undefined; 3.调用某个对象还没有添加的属性时,也会返回undefined; var obj={} ...
Set函数可以接受一个数组(或类似数组的对象)作为参数,用来初始化。 // 例一 var set = new Set([1, 2, 3, 4, 4]); [...set] // [1, 2, 3, 4] var s = new Set(); [2, 3, 5, 4, 5, 2, 2].map(x => s.add(x)); for...
JS是一门面向对象语言,其对象是用prototype属性来模拟的,下面,来看看如何封装JS对象. 常规封装 ...这种方式是比较常见的方式,比较直观,但是Person() 的职责是构造对象,如果把初始化的事情也放在里面完成,
前言 ...#初始化 LOGS_PATH=/usr/local/nginx/logs YESTERDAY=$(date -d yesterday +%Y%m%d) #按天切割日志 mv ${LOGS_PATH}/bbs.52itstyle.com.access.log ${LOGS_PATH}/bbs.52itstyle.com.access_$
想想我们在遇到多语句分支时是不是首先想到的是 switc...2.使用数组,查询直接索引定位, 一般来讲我们是连续的初始化数组,也就意味索引(type_func)到函数的映射要连续,所以使用数组索引在扩展上来讲:例如增删元素是
constructor应该是ES6中明确使用constructor来表示构造函数的,构造函数使用在class中,用来做初始化操作。当包含constructor的类被实例化时,构造函数将被调用。 来看例子: class AppComponent { public name: ...