avalon-logkit

Java中日志组件详解

发布于 2020-9-1 11:35
224浏览
0收藏

作为开发人员,我相信您对日志记录工具并不陌生。 Java还具有功能强大且功能强大的日志记录库。 但是拥有如此众多的日志记录工具和第三方程序包,如何确保每个组件都可以使用约定日志工具?

本文将和大家介绍一下 Java 主流的日志工具,以及相对应的使用场景。

基本介绍
在 java 的世界里有许多实现日志功能的工具,最早得到广泛使用的是 log4j,现在比较流行的是 slf4j+logback。作为开发人员,我们有时候需要封装一些组件(二方包)提供给其他人员使用,但是那么多的日志工具,根本没法保证每个组件里都能使用约定好的日志工具,况且还有很多第三方的包,鬼知道他会用什么日志工具。假如一个应用程序用到了两个组件,恰好两个组件使用不同的日志工具,那么应用程序就会有两份日志输出了,蛋疼吧。。

下面简单介绍下常见的日志工具:

JUL
JUL 全称 java.util.logging.Logger,JDK 自带的日志系统,从 JDK1.4 就有了。因为 log4j 的存在,这个 logger 一直沉默着,其实在一些测试性的代码中,jdk 自带的 logger 比 log4j 更方便。JUL 是自带具体实现的,与 log4j、logback 等类似,而不是像 JCL、slf4j 那样的日志接口封装。

import java.util.logging.Level;
import java.util.logging.Logger; private static final Logger LOGGER = Logger.getLogger(MyClass.class.getName());

相同名字的 Logger 对象全局只有一个;
一般使用圆点分隔的层次命名空间来命名 Logger;Logger 名称可以是任意的字符串,但是它们一般应该基于被记录组件的包名或类名,如 java.net 或 javax.swing;
配置文件默认使用 jre/lib/logging.properties,日志级别默认为 INFO;
可以通过系统属性 java.util.logging.config.file 指定路径覆盖系统默认文件;
日志级别由高到低依次为:SEVERE(严重)、WARNING(警告)、INFO(信息)、CONFIG(配置)、FINE(详细)、FINER(较详细)、FINEST(非常详细)。另外还有两个全局开关:OFF「关闭日志记录」和 ALL「启用所有消息日志记录」。
《logging.properties》文件中,默认日志级别可以通过.level= ALL 来控制,也可以基于层次命名空间来控制,按照 Logger 名字进行前缀匹配,匹配度最高的优先采用;日志级别只认大写;
JUL 通过 handler 来完成实际的日志输出,可以通过配置文件指定一个或者多个 hanlder,多个 handler 之间使用逗号分隔;handler 上也有一个日志级别,作为该 handler 可以接收的日志最低级别,低于该级别的日志,将不进行实际的输出;handler 上可以绑定日志格式化器,比如 java.util.logging.ConsoleHandler 就是使用的 String.format 来支持的;
配置文件示例:

handlers= java.util.logging.ConsoleHandler

.level= ALL
com.suian.logger.jul.xxx.level = CONFIG
com.suian.logger.jul.xxx.demo2.level = FINE
com.suian.logger.jul.xxx.demo3.level = FINER java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%1$tF %1$tT [%4$s] %3$s - %5$s %n

Apache Commons Logging
之前叫 Jakarta Commons Logging,简称 JCL,是 Apache 提供的一个通用日志 API,可以让应用程序不再依赖于具体的日志实现工具。

commons-logging 包中对其它一些日志工具,包括 Log4J、Avalon LogKit、JUL 等,进行了简单的包装,可以让应用程序在运行时,直接将 JCL API 打点的日志适配到对应的日志实现工具中。

common-logging 通过动态查找的机制,在程序运行时自动找出真正使用的日志库。这一点与 slf4j 不同,slf4j 是在编译时静态绑定真正的 Log 实现库。

commons-logging 包里的包装类和简单实现列举如下:

org.apache.commons.logging.impl.Jdk14Logger,适配 JDK1.4 里的 JUL;
org.apache.commons.logging.impl.Log4JLogger,适配 Log4J;
org.apache.commons.logging.impl.LogKitLogger,适配 avalon-Logkit;
org.apache.commons.logging.impl.SimpleLog,common-logging 自带日志实现类,它实现了 Log 接口,把日志消息都输出到系统错误流 System.err 中;
org.apache.commons.logging.impl.NoOpLog,common-logging 自带日志实现类,它实现了 Log 接口,其输出日志的方法中不进行任何操作;
如果只引入 Apache Commons Logging,也没有通过配置文件《commons-logging.properties》进行适配器绑定,也没有通过系统属性或者 SPI 重新定义 LogFactory 实现,默认使用的就是 jdk 自带的 java.util.logging.Logger 来进行日志输出。

JCL 使用配置文件 commons-logging.properties,可以在该文件中指定具体使用哪个日志工具。不配置的话,默认会使用 JUL 来输出日志。配置示例:

Avalon LogKit
Avalon LogKit 是一个高速日志记录工具集,Avalon 里的各个组件 Framework、Excalibur、Cornerstone 和 Phoenix 都用到它。它的模型与 JDK 1.4 Logging package 采用相同的原理,但与 JDK 1.2+ 兼容。使用 LogKit 的原因是:Context 和 LogTargets。

使用 Log4j 的时候,日志的内容只能是一句话,而使用 LogKit,你可以记录很多项内容,甚至可以各项内容记录到对应的数据库字段中。如果使用 Log4j 存储日志到不同的存储介质,如数据库,需要使用 Appender,而 LogKit 已经可以支持多种存储目标。

log4j
Log4j 是 Apache 的一个开放源代码项目,通过使用 Log4j,我们可以控制日志信息输送的目的地是控制台、文件、数据库等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

Log4j 有 7 种不同的 log 级别,按照等级从低到高依次为:TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF。如果配置为 OFF 级别,表示关闭 log。Log4j 支持两种格式的配置文件:properties 和 xml。包含三个主要的组件:Logger、appender、Layout。

SLF4J
SLF4J 全称 The Simple Logging Facade for Java,简单日志门面,这个不是具体的日志解决方案,而是通过门面模式提供一些 Java Logging API,类似于 JCL。题外话,作者当时创建 SLF4J 的目的就是为了替代 Jakarta Commons Logging(JCL)。

SLF4J 提供的核心 API 是一些接口以及一个 LoggerFactory 的工厂类。在使用 SLF4J 的时候,不需要在代码中或配置文件中指定你打算使用哪个具体的日志系统,可以在部署的时候不修改任何配置即可接入一种日志实现方案,在编译时静态绑定真正的 Log 库。

使用 SLF4J 时,如果你需要使用某一种日志实现,那么你必须选择正确的 SLF4J 的 jar 包的集合(各种桥接包)。SLF4J 提供了统一的记录日志的接口,只要按照其提供的方法记录即可,最终日志的格式、记录级别、输出方式等通过具体日志系统的配置来实现,因此可以在应用中灵活切换日志系统。

logback 是 slf4j-api 的天然实现,不需要桥接包就可以使用。另外 slf4j 还封装了很多其他的桥接包,可以使用到其他的日志实现中,比如 slf4j-log4j12,就可以使用 log4j 进行底层日志输出,再比如 slf4j-jdk14,可以使用 JUL 进行日志输出。

Logback
Logback,一个“可靠、通用、快速而又灵活的 Java 日志框架”。Logback 当前分成三个模块:logback-core,logback- classic 和 logback-access。logback-core 是其它两个模块的基础模块。logback-classic 是 log4j 的一个改良版本,完整实现了 SLF4J API。

logback-access 模块与 Servlet 容器集成提供通过 Http 来访问日志的功能。Logback 依赖配置文件 logback.xml,当然也支持 groovy 方式。Logback 相比 log4j,有很多很多的优点,网上一搜一大片,此处就不再赘述了。

Log4j2
Log4j 2 是 log4j 1.x 和 logback 的改进版,据说采用了一些新技术(无锁异步等等),使得日志的吞吐量、性能比 log4j 1.x 提高 10 倍,并解决了一些死锁的 bug,而且配置更加简单灵活。

Log4j2 支持插件式结构,可以根据需要自行扩展 Log4j2,实现自己的 appender、logger、filter 等。在配置文件中可以引用属性,还可以直接替代或传递到组件,而且支持 json 格式的配置文件。不像其他的日志框架,它在重新配置的时候不会丢失之前的日志文件。

Log4j2 利用 Java5 中的并发特性支持,尽可能地执行最低层次的加锁。解决了在 log4j 1.x 中存留的死锁的问题。Log4j 2 是基于 LMAX Disruptor 库的。在多线程的场景下,和已有的日志框架相比,异步 logger 拥有 10 倍左右的效率提升。

Log4j2 体系结构:

使用场景
只使用 java.util.logging.Logger
最简单的场景,正式系统一般不会这么用,自己写点小 demo、测试用例啥的是可以这么用。不要任何第三方依赖,jdk 原生支持。

只使用 Apache Commons Logging
需要引入 commons-logging 包,示例如下:

      <dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>

Apache Commons Logging 和 log4j 结合使用
需要引入 commons-logging 包和 log4j 包,示例如下:

      <dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

该模式下可以使用的打点 api:

org.apache.commons.logging.Log,commons-logging 里的 api;
org.apache.log4j.Logger,log4j 里的 api;
无论使用哪种 api 打点,最终日志都会通过 log4j 进行实际的日志记录。推荐用 commons-logging 里的 api,如果直接用 log4j 里的 api,就跟单用 log4j 没区别,就没有再引入 commons-logging 包的必要了。

既然最终是通过 log4j 实现日志记录,那么日志输出的 level、target 等也就是通过 log4j 的配置文件进行控制了。下面是一个 log4j 配置文件《log4j.properties》的简单示例:

log4j.logger.com.suian.logtest = trace,console

#输出源 console 输出到控制台
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %-5p %c - [log4j]%m%n

既然是推荐使用 commons-logging 里的 api 打点,为了能找到 log4j 的日志实现,必须通过《commons-logging.properties》配置文件显式的确定关联,示例如下:

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

代码中使用 JCL api 进行日志打点,底层使用 log4j 进行日志输出。日志输出控制依托于 log4j 的配置文件,另外需要在 commons-logging.properties 配置文件中显式指定与 log4j 的绑定关系。

单独使用 log4j
这个是早几年最最流行的用法了,现在因为 log4j 本身的问题以及新的日志框架的涌现,已经逐步退出历史舞台了。具体怎么用自己去百度吧。

SLF4J 结合 Logback
当下最流行的用法,SLF4J 为使用场景最广泛的日志门面,加上 Logback 的天然实现,简单、统一、快速。

需要引入第三方依赖:

      <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>

单独使用 Log4j2
Log4j2 感觉就是 SLF4J+Logback。log4j-api 等价于 SLF4J,log4j-core 等价于 Logback。

需要引入第三方依赖:

      <dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>

冲突处理
理论上各种日志输出方式是可以共存的,比如 log4j 和 log4j2 以及 logback 等,但是麻烦的是我们得维护多个配置文件,必须充分了解每个组件使用的是那种日志组件,然后进行对应的配置文件配置。

如何解决呢?每一个想做通用日志解决方案的,都对兼容性问题进行了特殊处理。目前只有 slf4j 和 log4j2 提供了这样的整合机制,其他的基本都很弱。

代码中可能使用的日志打点 Api 列举:

java.util.logging.Logger,jdk 自带的;
org.apache.commons.logging.Log,commons-logging 包里的 api;
org.apache.log4j.Logger,log4j 包里的 api;
org.apache.logging.log4j.Logger,log4j2 提供的 api,在 log4j-api 包里;
org.slf4j.Logger,slf4j 提供的 api,在 slf4j-api 包里;
上述打点方式,在一个应用中是有可能共存的,即使自己写的代码可以确保都使用同一类 api,但是引入的第三方依赖里就可能各式各样了。该怎么处理呢?

前面已经提过了,现在能够对各类冲突支持比较到位的就是 slf4j 和 log4j2,他们都提供了很多的绑定器和桥接器。

所谓的绑定器,也可以称之为适配器或者包装类,就是将特定 api 打点的日志绑定到具体日志实现组件来输出。比如 JCL 可以绑定到 log4j 输出,也可以绑定到 JUL 输出;再比如 slf4j,可以通过 logback 输出,也可以绑定到 log4j、log4j2、JUL 等;
所谓的桥接器就是一个假的日志实现工具,比如当你把 jcl-over-slf4j.jar 放到 CLASS_PATH 时,即使某个组件原本是通过 JCL 输出日志的,现在却会被 jcl-over-slf4j “骗到”SLF4J 里,然后 SLF4J 又会根据绑定器把日志交给具体的日志实现工具。
slf4j 整合日志输出
java.util.logging.Logger
将 JUL 日志整合到 slf4j 统一输出,需要引入 slf4j 提供的依赖包:

      <dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.22</version>
</dependency>

只引入依赖并不能整合 JUL 日志,该包里只是提供了一个 JUL 的 handler,仍旧需要通过 JUL 的配置文件进行配置,slf4j 绑定器(如 logback)上设置的日志级别等价于 JUL handler 上的日志级别,因此控制 JUL 的日志输出,日志级别仍旧分两个地方控制:JUL 配置文件《logging.properties》和 slf4j 绑定器的配置文件,比如《logback.xml》、《log4j2.xml》等。

建立 jdk14-logger 的配置文件《logger.properties》,加入 handler 配置以及日志级别配置;

handlers= org.slf4j.bridge.SLF4JBridgeHandler
.level= ALL

在启动程序或容器的时候加入 JVM 参数配置 -Djava.util.logging.config.file = /path/logger.properties;当然也可以使用编程方式进行处理,可以在 main 方法或者扩展容器的 listener 来作为系统初始化完成;此种方式有些场景下不如配置 JVM 参数来的彻底,比如想代理 tomcat 的系统输出日志,编程方式就搞不定了。
org.apache.commons.logging.Log
将 JCL 日志整合到 slf4j 统一输出,需要引入 slf4j 提供的依赖包:

      <dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.22</version>
</dependency>

jcl-over-slf4j 包里所有类的根路径为 org.apache.commons.logging,也有 Log 和 LogFactory 类,相当于以重写 commons-logging 包的代价来实现对 JCL 的桥接。Log 与 commons-logging 包里的一模一样,LogFactory 的实现,代码写死使用的是 org.apache.commons.logging.impl.SLF4JLogFactory。

commons-logging 包里默认使用的是 org.apache.commons.logging.impl.LogFactoryImpl。以这样的代价来实现桥接,可以实现无缝对接,不像 JUL 那样还得添加额外配置,但是有一个坏处就是需要处理类库冲突了。commons-logging 包和 jcl-over-slf4j 包肯定是不能共存的,需要将 commons-logging 包在 classpath 里排掉。

题外话,因为 JCL 本身就支持通过配置文件《commons-logging.properties》绑定适配器,所以个人感觉更倾向于封装一个适配器的方式来支持,就像 commons-logging 包里的 org.apache.commons.logging.impl.Log4JLogger,这样更符合程序员的思维,明明白白。

桥接包的命名也是很讲究的,覆写的这种,命名为 xxx-over-slf4j,如本例的 jcl-over-slf4j;纯桥接的,命名为 xxx-to-slf4j,如文章前面提到的 jul-to-slf4j。

org.apache.log4j.Logger
将 log4j 日志整合到 slf4j 统一输出,需要引入 slf4j 提供的依赖包:

      <dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.22</version>
</dependency>

看桥接包的名字就知道了,log4j-over-slf4j 肯定是覆写了 log4j:log4j 包,因此使用起来只需要引入依赖即可,不需要其他额外的配置。但是仍旧是要处理冲突的,log4j 包和 log4j-over-slf4j 是不能共存的哦。

org.apache.logging.log4j.Logger
将 log4j2 日志整合到 slf4j 统一输出,slf4j 没有提供桥接包,但是 log4j2 提供了,原理是一样的,首先引入 log4j2 的桥接包:

      <dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.6.2</version>
</dependency>

log4j2 提供的依赖包有 org.apache.logging.log4j:log4j-api 和 org.apache.logging.log4j:log4j-core,其作用看包名就清楚了。log4j-core 是 log4j-api 的标准实现,同样 log4j-to-slf4j 也是 log4j-api 的一个实现。

log4j-to-slf4j 用于将 log4j2 输出的日志桥接到 slf4j 进行实际的输出,作用上来讲,log4j-core 和 log4j-to-slf4j 是不能共存的,因为会存在两个 log4j2 的实现。

经测试,就测试结果分析,共存也是木有问题的,何解?log4j2 加载 provider 的时候采用了优先级策略,即使找到多个也能决策出一个可用的 provider 来。在所有提供 log4j2 实现的依赖包中,都有一个 META-INF/log4j-provider.properties 配置文件,里面的 FactoryPriority 属性就是用来配置 provider 优先级的,幸运的是 log4j-to-slf4j(15)的优先级是高于 log4j-core(10)的,因此测试结果符合预期,log4j2 的日志桥接到了 slf4j 中进行输出。

同样,为确保系统的确定性,不会因为 log4j2 的 provider 决策策略变更导致问题,建议还是要在 classpath 里排掉 log4j-core,log4j2 也是推荐这么做的。

log4j2 整合日志输出
java.util.logging.Logger
将 JUL 日志整合到 log4j2 统一输出,需要引入 log4j2 提供的依赖包:

      <dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
<version>2.6.2</version>
</dependency>

log4j2 整合 JUL 日志的方式与 slf4j 不同,slf4j 只是定义了一个 handler,仍旧依赖 JUL 的配置文件;log4j2 则直接继承重写了 java.util.logging.LogManager。

使用时,只需要通过系统属性 java.util.logging.manager 绑定重写后的 LogManager(org.apache.logging.log4j.jul.LogManager)即可,感觉比 slf4j 的方式要简单不少。

org.apache.commons.logging.Log
将 JCL 日志整合到 log4j2 统一输出,需要引入 log4j2 提供的依赖包:

      <dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.6.2</version>
</dependency>

基于 log4j-jcl 包整合 JCL 比较简单,只要把 log4j-jcl 包扔到 classpath 就可以了。看起来 slf4j 的整合方式优雅多了,底层原理是这样的:JCL 的 LogFactory 在初始化的时候,查找 LogFactory 的具体实现,是分了几种场景的,简单描述如下:

首先根据系统属性 org.apache.commons.logging.LogFactory 查找 LogFactory 实现类;
如果找不到,则以 SPI 方式查找实现类,META-INF/services/org.apache.commons.logging.LogFactory;log4j-jcl 就是以这种方式支撑的;此种方式必须确保整个应用中,包括应用依赖的第三方 jar 包中,org.apache.commons.logging.LogFactory 文件只有一个,如果存在多个的话,哪个先被加载则以哪个为准。万一存在冲突的话,排查起来也挺麻烦的。
还找不到,则读取《commons-logging.properties》配置文件,使用 org.apache.commons.logging.LogFactory 属性指定的 LogFactory 实现类;
最后再找不到,就使用默认的实现 org.apache.commons.logging.impl.LogFactoryImpl。
org.apache.log4j.Logger
将 log4j 1.x 日志整合到 log4j2 统一输出,需要引入 log4j2 提供的依赖包:

      <dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.6.2</version>
</dependency>

log4j2 里整合 log4j 1.x 日志,也是通过覆写 log4j 1.x api 的方式来实现的,跟 slf4j 的实现原理一致。因此也就存在类库冲突的问题,使用 log4j-1.2-api 的话,必须把 classpath 下所有 log4j 1.x 的包清理掉。

org.slf4j.Logger
将 slf4j 日志整合到 log4j2 统一输出,需要引入 log4j2 提供的依赖包:

      <dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.6.2</version>
</dependency>

log4j-slf4j-impl 基于 log4j2 实现了 slf4j 的接口,其就是 slf4j-api 和 log4j2-core 之间的一个桥梁。这里有个问题需要注意下,务必确保 classpath 下 log4j-slf4j-impl 和 log4j-to-slf4j 不要共存,否则会导致事件无止尽地在 SLF4J 和 Log4j2 之间路由。

日志打点 API 绑定实现
slf4j-api 和 log4j-api 都是接口,不提供具体实现,理论上基于这两种 api 输出的日志可以绑定到很多的日志实现上。slf4j 和 log4j2 也确实提供了很多的绑定器。简单列举几种可能的绑定链:

slf4j → logback
slf4j → slf4j-log4j12 → log4j
slf4j → log4j-slf4j-impl → log4j2
slf4j → slf4j-jdk14 → jul
slf4j → slf4j-jcl → jcl
jcl → jul
jcl → log4j
log4j2-api → log4j2-cor
log4j2-api → log4j-to-slf4j → slf4j
来个环图:

本文转载自公众号淘系技术(ID:AlibabaMTT)。

Java中日志组件详解的更多相关文章

  1. Android中Intent组件详解

    Intent是不同组件之间相互通讯的纽带,封装了不同组件之间通讯的条件.Intent本身是定义为一个类别(Class),一个Intent对象表达一个目的(Goal)或期望(Expectation),叙 ...

  2. java中的注解详解和自定义注解

    一.java中的注解详解 1.什么是注解 用一个词就可以描述注解,那就是元数据,即一种描述数据的数据.所以,可以说注解就是源代码的元数据.比如,下面这段代码: @Override public Str ...

  3. Java中dimension类详解

    Java中dimension类详解 https://blog.csdn.net/hrw1234567890/article/details/81217788

  4. [转载]java中import作用详解

    [转载]java中import作用详解 来源: https://blog.csdn.net/qq_25665807/article/details/74747868 这篇博客讲的真的很清楚,这个作者很 ...

  5. java Log4j日志配置详解大全

    一.Log4j简介 Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局).这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出.综合使 ...

  6. Java中反射机制详解

    序言 在学习java基础时,由于学的不扎实,讲的实用性不强,就觉得没用,很多重要的知识就那样一笔带过了,像这个马上要讲的反射机制一样,当时学的时候就忽略了,到后来学习的知识中,很多东西动不动就用反射, ...

  7. JAVA中Object类方法详解

    一.引言 Object是java所有类的基类,是整个类继承结构的顶端,也是最抽象的一个类.大家天天都在使用toString().equals().hashCode().waite().notify() ...

  8. java中Class对象详解和类名.class, class.forName(), getClass()区别

    一直在想.class和.getClass()的区别,思索良久,有点思绪,然后有网上搜了搜,找到了如下的一篇文章,与大家分享. 原来为就是涉及到Java的反射----- Java反射学习 所谓反射,可以 ...

  9. Java中的多线程详解

    如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个话其 ...

随机推荐

  1. 解决“用PicGo-2.3.0-beta5 + GitHub做博客图床,github仓库图片文件不显示”的问题记录(备忘)

    解决"用PicGo-2.3.0-beta5 + GitHub做博客图床,github仓库图片文件不显示"的问题记录(备忘) 历时几个小时百度,终于靠自己理解解决了GitHub仓库图 ...

  2. 浅入Kubernetes(7):应用部署实例,Deployment、Service、ReplicaSet

    目录 Deployment 创建 Deployment kubectl apply/create 网络端口映射和更新 Deployment ReplicaSet 在本文之前,你需要阅读: 尝试 kub ...

  3. GoF设计模式合集

    1 概述 这篇文章是对GoF23种设计模式+1种非GoF模式的合集,由笔者自己的笔记整理而来,每个模式都详细描述了步骤,角色等,以及使用Java实现的具体的例子. 2 基础 设计模式概述 UML与面向 ...

  4. day9.函数2

    一.函数对象 函数是第一类对象,第一等公民,函数对象即函数可以被当作变量去用. 具体分为四个方面: 1.可以被赋值 def func(): print('from func') f = func pr ...

  5. Day09_47_Map

    Map 集合 Map集合** 继承关系** <interface>: Map(接口)<---HashMap(class)/HashTable(class)/SortedMap(子接口 ...

  6. java面试一日一题:讲下mysql中的索引

    问题:请讲下mysql中的索引 分析:mysql中有很多索引,要对对这些索引有所掌握,还要弄清楚每种索引的本质? 回答要点: 主要从以下几点去考虑 1.索引的本质是什么 2.mysql的索引分类: 3 ...

  7. 【DB宝50】Oracle异构平台迁移之完全可传输导出导入(Full Transportable Export & Import)

    目录 一.简介 1.1.使用场景 1.2.限制条件 二.完全可传输操作步骤 三.案例演示 3.1.环境 3.2.源库操作 3.2.1.将需要传输的用户表空间设置为RO状态 3.2.2.使用Data P ...

  8. hdu4717 三分(散点的移动)

    题意:      给你一些点,这些点有各自的初始位置,移动速度和方向,问你什么时候任意两点中最长的距离最小,求时刻和此时的距离.. 思路:      感觉题目很赞,一开始想不到三分,因为么有办法证明他 ...

  9. Linux中编写Shell脚本

    目录 Shell Shell脚本的执行 Shell脚本编写规范 Shell 中的变量 变量的算术运算 双小括号 (())  数值运算命令的用法 let 运算命令的用法 expr 命令的用法 br 命令 ...

  10. Metasploit Framework(MSF)的使用

    目录 Metasploit 安装Metasploit 漏洞利用(exploit) 攻击载荷(payload) Meterpreter MS17_010(永恒之蓝) 辅助模块(探测模块) 漏洞利用模块 ...