spring日志加载代码解析

项目用的是springmvc+spring+mybatis框架,

配置日志的时候非常简单,仅仅是把commons-logging、log4j,还有slf4j-log4j三个日志相关的jar包导入项目,然后在classpath中加个log4j.properties的配置文件即可。

但是你有没有想过Log4j是什么时候被加载进虚拟机的?为什么我们没有手动加载,spring和mybatis就能自动的用起来log4j,毫不见外?

spring使用的是commons-logging

mybatis用的是自己写的

看一下源码,非常简单,一个个的去试,没有这个就进入下一个,直到找到了log4j

这两个工具其实都只是日志工具的规范,可以理解成接口,而log4j才是一个实实在在的日志实现。

但是slf4j在什么地方?——虽然这两个工具没用到slf4j,我还是把它放进来,因为我引入的其他工具会用到它。。比如:

下面开始看代码代码来说明一下log4j是怎么被加载到虚拟机的,并且为什么spring和mybatis都会用log4j:

首先我们来看spring,我们从web.xml看起,加载spring:

到这里我们看到了LogFactory,这是commons-logging的一个log工厂,这里用的是这个虚类的一个静态方法,我们继续看这个方法:

再看getFactory:

  1 public static LogFactory getFactory() throws LogConfigurationException {
  2         // Identify the class loader we will be using
  3         ClassLoader contextClassLoader = getContextClassLoaderInternal();
  4
  5         if (contextClassLoader == null) {
  6             // This is an odd enough situation to report about. This
  7             // output will be a nuisance on JDK1.1, as the system
  8             // classloader is null in that environment.
  9             if (isDiagnosticsEnabled()) {
 10                 logDiagnostic("Context classloader is null.");
 11             }
 12         }
 13
 14         // Return any previously registered factory for this class loader
 15         LogFactory factory = getCachedFactory(contextClassLoader);
 16         if (factory != null) {
 17             return factory;
 18         }
 19
 20         if (isDiagnosticsEnabled()) {
 21             logDiagnostic(
 22                     "[LOOKUP] LogFactory implementation requested for the first time for context classloader " +
 23                     objectId(contextClassLoader));
 24             logHierarchy("[LOOKUP] ", contextClassLoader);
 25         }
 26
 27         // Load properties file.
 28         //
 29         // If the properties file exists, then its contents are used as
 30         // "attributes" on the LogFactory implementation class. One particular
 31         // property may also control which LogFactory concrete subclass is
 32         // used, but only if other discovery mechanisms fail..
 33         //
 34         // As the properties file (if it exists) will be used one way or
 35         // another in the end we may as well look for it first.
 36
 37         Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES);
 38
 39         // Determine whether we will be using the thread context class loader to
 40         // load logging classes or not by checking the loaded properties file (if any).
 41         ClassLoader baseClassLoader = contextClassLoader;
 42         if (props != null) {
 43             String useTCCLStr = props.getProperty(TCCL_KEY);
 44             if (useTCCLStr != null) {
 45                 // The Boolean.valueOf(useTCCLStr).booleanValue() formulation
 46                 // is required for Java 1.2 compatibility.
 47                 if (Boolean.valueOf(useTCCLStr).booleanValue() == false) {
 48                     // Don‘t use current context classloader when locating any
 49                     // LogFactory or Log classes, just use the class that loaded
 50                     // this abstract class. When this class is deployed in a shared
 51                     // classpath of a container, it means webapps cannot deploy their
 52                     // own logging implementations. It also means that it is up to the
 53                     // implementation whether to load library-specific config files
 54                     // from the TCCL or not.
 55                     baseClassLoader = thisClassLoader;
 56                 }
 57             }
 58         }
 59
 60         // Determine which concrete LogFactory subclass to use.
 61         // First, try a global system property
 62         if (isDiagnosticsEnabled()) {
 63             logDiagnostic("[LOOKUP] Looking for system property [" + FACTORY_PROPERTY +
 64                           "] to define the LogFactory subclass to use...");
 65         }
 66
 67         try {
 68             String factoryClass = getSystemProperty(FACTORY_PROPERTY, null);
 69             if (factoryClass != null) {
 70                 if (isDiagnosticsEnabled()) {
 71                     logDiagnostic("[LOOKUP] Creating an instance of LogFactory class ‘" + factoryClass +
 72                                   "‘ as specified by system property " + FACTORY_PROPERTY);
 73                 }
 74                 factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
 75             } else {
 76                 if (isDiagnosticsEnabled()) {
 77                     logDiagnostic("[LOOKUP] No system property [" + FACTORY_PROPERTY + "] defined.");
 78                 }
 79             }
 80         } catch (SecurityException e) {
 81             if (isDiagnosticsEnabled()) {
 82                 logDiagnostic("[LOOKUP] A security exception occurred while trying to create an" +
 83                               " instance of the custom factory class" + ": [" + trim(e.getMessage()) +
 84                               "]. Trying alternative implementations...");
 85             }
 86             // ignore
 87         } catch (RuntimeException e) {
 88             // This is not consistent with the behaviour when a bad LogFactory class is
 89             // specified in a services file.
 90             //
 91             // One possible exception that can occur here is a ClassCastException when
 92             // the specified class wasn‘t castable to this LogFactory type.
 93             if (isDiagnosticsEnabled()) {
 94                 logDiagnostic("[LOOKUP] An exception occurred while trying to create an" +
 95                               " instance of the custom factory class" + ": [" +
 96                               trim(e.getMessage()) +
 97                               "] as specified by a system property.");
 98             }
 99             throw e;
100         }
101
102         // Second, try to find a service by using the JDK1.3 class
103         // discovery mechanism, which involves putting a file with the name
104         // of an interface class in the META-INF/services directory, where the
105         // contents of the file is a single line specifying a concrete class
106         // that implements the desired interface.
107
108         if (factory == null) {
109             if (isDiagnosticsEnabled()) {
110                 logDiagnostic("[LOOKUP] Looking for a resource file of name [" + SERVICE_ID +
111                               "] to define the LogFactory subclass to use...");
112             }
113             try {
114                 final InputStream is = getResourceAsStream(contextClassLoader, SERVICE_ID);
115
116                 if( is != null ) {
117                     // This code is needed by EBCDIC and other strange systems.
118                     // It‘s a fix for bugs reported in xerces
119                     BufferedReader rd;
120                     try {
121                         rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
122                     } catch (java.io.UnsupportedEncodingException e) {
123                         rd = new BufferedReader(new InputStreamReader(is));
124                     }
125
126                     String factoryClassName = rd.readLine();
127                     rd.close();
128
129                     if (factoryClassName != null && ! "".equals(factoryClassName)) {
130                         if (isDiagnosticsEnabled()) {
131                             logDiagnostic("[LOOKUP]  Creating an instance of LogFactory class " +
132                                           factoryClassName +
133                                           " as specified by file ‘" + SERVICE_ID +
134                                           "‘ which was present in the path of the context classloader.");
135                         }
136                         factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader );
137                     }
138                 } else {
139                     // is == null
140                     if (isDiagnosticsEnabled()) {
141                         logDiagnostic("[LOOKUP] No resource file with name ‘" + SERVICE_ID + "‘ found.");
142                     }
143                 }
144             } catch (Exception ex) {
145                 // note: if the specified LogFactory class wasn‘t compatible with LogFactory
146                 // for some reason, a ClassCastException will be caught here, and attempts will
147                 // continue to find a compatible class.
148                 if (isDiagnosticsEnabled()) {
149                     logDiagnostic(
150                         "[LOOKUP] A security exception occurred while trying to create an" +
151                         " instance of the custom factory class" +
152                         ": [" + trim(ex.getMessage()) +
153                         "]. Trying alternative implementations...");
154                 }
155                 // ignore
156             }
157         }
158
159         // Third try looking into the properties file read earlier (if found)
160
161         if (factory == null) {
162             if (props != null) {
163                 if (isDiagnosticsEnabled()) {
164                     logDiagnostic(
165                         "[LOOKUP] Looking in properties file for entry with key ‘" + FACTORY_PROPERTY +
166                         "‘ to define the LogFactory subclass to use...");
167                 }
168                 String factoryClass = props.getProperty(FACTORY_PROPERTY);
169                 if (factoryClass != null) {
170                     if (isDiagnosticsEnabled()) {
171                         logDiagnostic(
172                             "[LOOKUP] Properties file specifies LogFactory subclass ‘" + factoryClass + "‘");
173                     }
174                     factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
175
176                     // TODO: think about whether we need to handle exceptions from newFactory
177                 } else {
178                     if (isDiagnosticsEnabled()) {
179                         logDiagnostic("[LOOKUP] Properties file has no entry specifying LogFactory subclass.");
180                     }
181                 }
182             } else {
183                 if (isDiagnosticsEnabled()) {
184                     logDiagnostic("[LOOKUP] No properties file available to determine" + " LogFactory subclass from..");
185                 }
186             }
187         }
188
189         // Fourth, try the fallback implementation class
190
191         if (factory == null) {
192             if (isDiagnosticsEnabled()) {
193                 logDiagnostic(
194                     "[LOOKUP] Loading the default LogFactory implementation ‘" + FACTORY_DEFAULT +
195                     "‘ via the same classloader that loaded this LogFactory" +
196                     " class (ie not looking in the context classloader).");
197             }
198
199             // Note: unlike the above code which can try to load custom LogFactory
200             // implementations via the TCCL, we don‘t try to load the default LogFactory
201             // implementation via the context classloader because:
202             // * that can cause problems (see comments in newFactory method)
203             // * no-one should be customising the code of the default class
204             // Yes, we do give up the ability for the child to ship a newer
205             // version of the LogFactoryImpl class and have it used dynamically
206             // by an old LogFactory class in the parent, but that isn‘t
207             // necessarily a good idea anyway.
208             factory = newFactory(FACTORY_DEFAULT, thisClassLoader, contextClassLoader);
209         }
210
211         if (factory != null) {
212             /**
213              * Always cache using context class loader.
214              */
215             cacheFactory(contextClassLoader, factory);
216
217             if (props != null) {
218                 Enumeration names = props.propertyNames();
219                 while (names.hasMoreElements()) {
220                     String name = (String) names.nextElement();
221                     String value = props.getProperty(name);
222                     factory.setAttribute(name, value);
223                 }
224             }
225         }
226
227         return factory;
228     }

以上代码会先视图从classpath中加载commons-logging.properties等几个commons-logging才有的东西,直到208行代码,

我们看到最后创建了一个LogFactoryImpl的实例,然后返回了。

回头看看我们上边的代码:

看完了getFactory我们知道最后我们得到的是LogFactoryImpl的实例,

那么接下来我们该去这个类中看看它的getInstance方法了:

非常简单,在这里创建了一个Log的实例,这也是最关键的地方,我们去看看这个方法。

经过我个人进一步的代码分析logConstructor这个东西是空的,我就不再展开了,这时我们看541行这个方法,这里才是真正的创建Log实例:

这个方法名我们能看懂,就是去发现系统中的Log实现,也就是一个找的过程,后边的782行是找找系统变量中有没有commons-logging自己的指明实现类类名的变量,结果是没有的。

这个方法还没完,中间是一大段的注释,我们直接看后边的重点:

这个时候开始遍历一个字符串数组,依此去系统中找有没有这个数组中的实现类,我们看看这个数组先。

大家看到了什么?log4j,现在大家基本已经知道为什么了,后边的代码如果还有兴趣可以自己去看,其实就是一个个的试着去系统中加载这些类,加载不到处理一下ClassNotFoundException然后继续找下一个。

完毕。

最后如果大家想看看commons-logging自己的日志,可以写一个Listener放在web xml第一个位置,把下边一句代码弄上:

你们会从日志中看到多了很多内容,其中有一句是:

[[email protected] from [email protected]] Class ‘org.apache.commons.logging.impl.Log4JLogger‘ was found at ‘jar:file:/E:/eaipweb/wtpwebapps/EAIP/WEB-INF/lib/commons-logging-1.1.1.jar!/org/apache/commons/logging/impl/Log4JLogger.class‘

这回真完毕了。

时间: 2024-10-26 12:59:05

spring日志加载代码解析的相关文章

关于tomcat下spring无法加载依赖jar中properties文件的原因分析

我们经常把spring需要加载的properties文件放在java/resources下面,这样存放的问题导致properties在打包后就在jar的根目录下,所以我们的spring的配置路径就是classpath*:xxx.properties,但是这样的jar我们在被其他项目引用的时候会发现properties文件老是无法加载,就这个问题从spring的源码来找找为什么会这样. 首先properties是当做一个resource来加载的,实现加载的是org.springframework.

Spring Boot加载配置文件的完整步骤

这篇文章主要给大家介绍了关于Spring Boot加载配置文件的完整步骤,文中通过示例代码介绍的非常详细,对大家的学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧 前言 本文针对版本2.2.0.RELEASE来分析SpringBoot的配置处理源码,通过查看SpringBoot的源码来弄清楚一些常见的问题比如: SpringBoot从哪里开始加载配置文件? SpringBoot从哪些地方加载配置文件? SpringBoot是如何支持yaml和proper

Android异步加载全解析之Bitmap

Android异步加载全解析之Bitmap 在这篇文章中,我们分析了Android在对大图处理时的一些策略--Android异步加载全解析之大图处理  戳我戳我 那么在这篇中,我们来对图像--Bitmap进行一个更加细致的分析,掌握Bitmap的点点滴滴. 引入 Bitmap这玩意儿号称Android App头号杀手,特别是3.0之前的版本,简直就是皇帝般的存在,碰不得.摔不得.虽然后面的版本Android对Bitmap的管理也进行了一系列的优化,但是它依然是非常难处理的一个东西.在Androi

Android异步加载全解析之使用多线程

异步加载之使用多线程 初次尝试 异步.异步,其实说白了就是多任务处理,也就是多线程执行,多线程那就会有各种问题,我们一步步来看,首先,我们创建一个class--ImageLoaderWithoutCaches,从命名上,大家也看出来,这个类,我们实现的是不带缓存的图像加载,不多说,我们再创建一个方法--showImageByThread,通过多线程来加载图像: /** * Using Thread * @param imageView * @param url */ public void sh

浏览器加载、解析、渲染的过程

最近在学习性能优化,学习了雅虎军规 ,可是觉着有点云里雾里的,因为里面有些东西虽然自己也一直在使用,但是感觉不太明白所以然,比如减少DNS查询,css和js文件的顺序.所以就花了时间去了解浏览器的工作,有一篇经典的文章<how browsers work> ,讲的很详细,也有中文译本 .不过就是文章有点太长,也讲了一堆东西,还是自己总结一下. 为什么要了解浏览器加载.解析.渲染这个过程? 好,我们先说一下,为什么要了解这些呢?如果想写出一个最佳实践的页面,就要好好了解. 了解浏览器如何进行加载

浏览器~加载,解析,渲染

昨天为了 了解浏览器是怎么处理(.html..css..js)这些文件,我看了网上的好多资料,这好多资料中,有很多是通过转载.或是转载后加之自己的理解,但是因为自己对专业的词汇理解不好,还有一些作者将不同浏览器的处理过程混着说,总之,看完了,还是有很多疑虑的地方.我先根据昨天了解到的内容总结一下,日后随着学的深了,再回过来补充.2014.11.6 why 为什么要了解浏览器加载.解析.渲染这个过程? 了解浏览器如何进行加载,我们可以在引用外部样式文件,外部js时,将他们放到合适的位置,使浏览器以

Spring中加载xml配置文件的六种方式

因为目前正在从事一个项目,项目中一个需求就是所有的功能都是插件的形式装入系统,这就需要利用Spring去动态加载某一位置下的配置文件,所以就总结了下Spring中加载xml配置文件的方式,我总结的有6种, xml是最常见的spring 应用系统配置源.Spring中的几种容器都支持使用xml装配bean,包括: XmlBeanFactory,ClassPathXmlApplicationContext,FileSystemXmlApplicationContext,XmlWebApplicati

通过DexClassLoader动态加载代码

动态加载代码,会有多种需求,有的是APK过大,想缩小点:有的是部分代码需要灵活变动,例如视频站点的解析规则. 奉上一个Demo,在这个demo中验证了从dexclassloader加载 1.db 2.,sharedpreference 3.webview 4. so库 5.context 6.传入listener回调 7.加载不同package下的类 欢迎大家下载: http://download.csdn.net/download/ameryzhu/8970167 版权声明:本文为博主原创文章

HTML页面加载和解析流程详细介绍

浏览器加载和渲染html的顺序.如何加快HTML页面加载速度.HTML页面加载和解析流程等等,在本文将为大家详细介绍下,感兴趣的朋友不要错过 浏览器加载和渲染html的顺序 1. IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的. 2. 在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(并不是说所有相关联的元素都已经下载完). 3. 如果遇到语义解释性的标签嵌入文件(JS脚本,CSS样式),那么此时IE的下载过程会启用单独连接进行下载. 4. 样式表在下载完成后,