了解一下Java的日志体系

2023-11-08

目录

了解日子框架体系

分析日志框架如何转换

logback日志的集成

SpringBoot日志使用

   常见的一些日志框架如,commons-logging.jar、log4j.jar、sl4j-api.jar等,他们之间是存在一定关系的,在实际开发中可能就存在日志框架替换的问题,所以只有了解这些框架之间的关系,才能去解决问题。

了解日子框架体系

     在以前我们只是纯粹使用System.out.println("")来打印输出,这不仅影响性能,在实际线上遇到问题时还很不方便定位问题位置。后来为了定位问题方便出现了日志框架,最初的开源框架log4j 也是收到广大开发者欢迎,之后jdk也推出日志框架jui (java.util.logging),后面又开发了一个日志门面slf4j,(它不实现日志功能,只是用于整合日志的,需要适配去,桥接器去转换)。

早期的log4j框架写的代码是这样的

import org.apache.log4j.Logger;
\\省略
Logger logger = Logger.getLogger(Test.class);
logger.trace("trace");
\\省略

之后sun公司对于log4j的出现内心隐隐表示嫉妒。于是在jdk1.4版本后,增加了一个包为java.util.logging,简称为jul,用以对抗log4j。如下所示 

import java.util.logging.Logger;
\\省略
Logger loggger = Logger.getLogger(Test.class.getName()); 
logger.finest("finest");
\\省略

可以看出,api完全是不同的。那有没有办法,将这些api抽象出接口,这样以后调用的时候,就调用这些接口就好了呢?

      这个时候jcl(Jakarta Commons Logging)出现了,说jcl可能大家有点陌生,那么commons-logging-xx.jar组件,大家总有印象吧。JCL 只提供 log 接口,具体的实现则在运行时动态寻找。这样一来组件开发者只需要针对 JCL 接口开发,而调用组件的应用程序则可以在运行时搭配自己喜好的日志实践工具。JCL可以实现的集成方案如下图所示

jcl默认的配置:如果能找到Log4j 则默认使用log4j 实现,如果没有则使用jul(jdk自带的) 实现,再没有则使用jcl内部提供的SimpleLog 实现。于是,你在代码里变成这么写了

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
\\省略
Log log =LogFactory.getLog(Test.class);
log.trace('trace');
\\省略

     至于这个Log具体的实现类,JCL会在ClassLoader中进行查找。这么做,有三个缺点,缺点一是效率较低,二是容易引发混乱,三是在使用了自定义ClassLoader的程序中,使用JCL会引发内存泄露。JCL动态查找机制进行日志实例化,执行顺序为:commons-logging.properties---->系统环境变量------->log4j--->jul--->simplelog---->nooplog

      于是log4j的作者觉得jcl不好用,自己又写了一个新的接口api,那么就是slf4j。关于slf4j的集成图如下所示

        理解slf4j日志门面了吗,它跟jcl机制不一样。 它只提供一个门面,至于你要使用什么日志框架,需要引入对应的实现日志框架。JCL 背靠JDK 自带jul .

Slf4j与其他各种日志组件的桥接说明

各种日志组件的桥接说明

jar包名

说明

slf4j-log4j12-1.7.13.jar

Log4j1.2版本的桥接器,你需要将Log4j.jar加入Classpath。

log4j-slf4j-impl.jar

Log4j2版本的桥接器,还需要log4j-api.jar log4j-core.jar

slf4j-jdk14-1.7.13.jar

java.util.logging的桥接器,Jdk原生日志框架。

slf4j-nop-1.7.13.jar

NOP桥接器,默默丢弃一切日志。

slf4j-simple-1.7.13.jar

一个简单实现的桥接器,该实现输出所有事件到System.err. 只有Info以及高于该级别的消息被打印,在小型应用中它也许是有用的。

slf4j-jcl-1.7.13.jar

Jakarta Commons Logging 的桥接器. 这个桥接器将Slf4j所有日志委派给Jcl。

logback-classic-1.0.13.jar(requires logback-core-1.0.13.jar)

Slf4j的原生实现,Logback直接实现了Slf4j的接口,因此使用Slf4j与Logback的结合使用也意味更小的内存与计算开销

 如图所示,应用调了sl4j-api,即日志门面接口。日志门面接口本身通常并没有实际的日志输出能力,它底层还是需要去调用具体的日志框架API的,也就是实际上它需要跟具体的日志框架结合使用。由于具体日志框架比较多,而且互相也大都不兼容,日志门面接口要想实现与任意日志框架结合可能需要对应的桥接器,上图红框中的组件即是对应的各种桥接器!

我们在代码中需要写日志,变成下面这么写

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//省略
Logger logger = LoggerFactory.getLogger(Test.class);
// 省略
logger.info("info");

         在代码中,并不会出现具体日志框架的api。程序根据classpath中的桥接器类型,和日志框架类型,判断出logger.info应该以什么框架输出!注意了,如果classpath中不小心引了两个桥接器,那会直接报错的!因此,在阿里的开发手册上才有这么一条:

强制:应用中不可直接使用日志系统(log4j、logback)中的 API ,而应依赖使用日志框架 SLF4J 中的 API 。使用门面模式的日志框架,有利于维护和各个类的日志处理方式的统一。

  • 如果要将jcl或jul 转slf4j呢?

分析日志框架如何转换

一个项目,一个模块用log4j,另一个模块用slf4j+log4j2,如何统一输出?

      这里就要用上slf4j的适配器,slf4j提供了各种各样的适配器,用来将某种日志框架委托给slf4j。其最明显的集成工作方式有如下:

       进行选择填空,将我们的案例里的条件填入,根据题意应该选log4j-over-slf4j适配器,于是就变成下面这张图

再比如:如何让spring以log4j2的形式输出?

spring默认使用的是jcl输出日志,由于你此时并没有引入Log4j的日志框架,jcl会以jul做为日志框架。此时集成图如下

 而你的应用中,采用了slf4j+log4j-core,即log4j2进行日志记录,那么此时集成图如下

那我们现在需要让spring以log4j2的形式输出?怎么办?

OK,第一种方案,走jcl-over-slf4j适配器,此时集成图就变成下面这样了

在这种方案下,spring框架中遇到日志输出的语句,就会如上图红线流程一样,最终以log4J2的形式输出!

OK,有第二种方案么?有,走jul-to-slf4j适配器,此时集成图如下

ps:这种情况下,记得在代码中执行
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();

假设,我们在应用中调用了sl4j-api,但是呢,你引了四个jar包,slf4j-api-xx.jar,slf4j-log4j12-xx.jar,log4j-xx.jar,log4j-over-slf4j-xx.jar,于是你就会出现如下尴尬的场面

 如上图所示,在这种情况下,你调用了slf4j-api,就会陷入死循环中!slf4j-api去调了slf4j-log4j12,slf4j-log4j12又去调用了log4j,log4j去调用了log4j-over-slf4j。最终,log4j-over-slf4j又调了slf4j-api,陷入死循环!

logback日志的集成

总结:

  1. SpringBoot底层也是使用slf4j+logback的方式进行日志记录
    1. logback桥接:logback-classic
  2. SpringBoot也把其他的日志都替换成了slf4j;
    1. log4j 适配: log4j-over-slf4j
    2. jul适配:jul-to-slf4j
    3. 这两个适配器都是为了适配Spring的默认日志:jcl

SpringBoot日志使用

  • 日志级别

可以设置TRACE,DEBUG,INFO,WARN,ERROR,FATAL或OFF之一

logging:
  level:
    root: INFO
    com.fairy.log: ERROR
    org.springframework.web: ERROR
    org.hibernate: DEBUG
  pattern:
    dateformat: '%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){red} %clr(${LOG_LEVEL_PATTERN:-%10p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}'
  file:
    name: ./logs/faity-info.log
    max-size: 10KB

可以使用logging.pattern.console 修改默认的控制的日志格式:

  • 文件输出

           默认情况下,Spring Boot仅记录到控制台,不写日志文件。如果除了控制台输出外还想写日志文件,则需要设置一个logging.file.name或logging.file.path属性(例如application.properties)。下表显示了如何logging.*一起使用这些属性:

logging.file.name

logging.file.path

实例

描述

(没有)

(没有)

仅控制台记录。

指定文件名

(没有)

my.log

写入指定的日志文件。

(没有)

具体目录

/var/log

写入spring.log指定的目录。

  • logging.file.name
    • 可以设置文件的名称, 如果没有设置路径会默认在项目的相对路径下
    • 还可以指定路径+文件名:name: D:/xushu.log
  • logging.file.path
    • 不可以指定文件名称, 必须要指定一个物理文件夹路径,会默认使用spring.log
  • 日志迭代(轮转)

      如果你使用的是Logback,则可以使用application.properties或application.yaml文件微调日志轮播设置。对于所有其他日志记录系统,您需要直接自己配置轮转设置(例如,如果使用Log4J2,则可以添加log4j.xml文件)

名称

描述

logging.logback.rollingpolicy.file-name-pattern

归档的文件名

logging.logback.rollingpolicy.clean-history-on-start

如果应在应用程序启动时进行日志归档清理。

logging.logback.rollingpolicy.max-file-size

归档前日志文件的最大大小。

logging.logback.rollingpolicy.total-size-cap

删除日志档案之前可以使用的最大大小。

logging.logback.rollingpolicy.max-history

保留日志存档的天数(默认为7)

  • logging.logback.rollingpolicy.file-name-pattern
    • ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
      • ${LOG_FILE} 对应 logging.file.name
      • %d{yyyy-MM-dd} 日期 年-月-日
      • %i 索引, 当文件超出指定大小后进行的文件索引递增
  • 自定义日志配置文件

可以通过在类路径中包含适日志配置文件来激活各种日志记录系统或使用logging.config

Logging System

Customization

Logback

logback-spring.xml, logback-spring.groovy, logback.xml, or logback.groovy

Log4j2

log4j2-spring.xml or log4j2.xml

JDK (Java Util Logging)

logging.properties

注意:

  • 如果使用自定义日志配置文件 会使用springboot中全局配置文件的logging相关配置失效
  • 结合SpringBoot提供Profile来控制日志的生效
    • 注意: 一定要将日志配置文件的文件名改成logback-spring.xml, 因为 logback.xml 会在Springboot容器加载前先被logback给加载到, 那么由于logback无法解析springProfile 将会报错:
    • ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]] ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <!-- 格式 -->
        <springProfile name="dev">
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{100} ======= %msg%n</pattern>
        </springProfile>
        <springProfile name="!dev">
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{100} ++++++ %msg%n</pattern>
        </springProfile>

    </encoder>
</appender>
  • 切换日志框架
  • 将 logback切换成log4j2
  1. 将logback的场景启动器排除(slf4j只能运行有1个桥接器)
  2. 添加log4j2的场景启动器
  3. 添加log4j2的配置文件
<dependencies>
    <dependency>
        <!--starter-web里面自动添加starter-logging 也就是logback的依赖-->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <!--排除starter-logging 也就是logback的依赖-->
            <exclusion>
                <artifactId>spring-boot-starter-logging</artifactId>
                <groupId>org.springframework.boot</groupId>
            </exclusion>
        </exclusions>
    </dependency>

    <!--Log4j2的场景启动器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
</dependencies>
  • 将 logback切换成log4j
  1. 要将logback的桥接器排除
<dependency>
    <!--starter-web里面自动添加starter-logging 也就是logback的依赖-->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>logback-classic</artifactId>
            <groupId>ch.qos.logback</groupId>
        </exclusion>
    </exclusions>
</dependency>
  1. 添加log4j的桥接器
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
</dependency>
  1. 添加log4j的配置文件

log4j.properties

#trace<debug<info<warn<error<fatal
log4j.rootLogger=trace, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

举一个logback.xml的例子:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
    <contextName>logback</contextName>
    <!--定义日志文件的存储地址, 这里设置为项目的根目录-->
    <property name="log.path" value="/logs" />
    <!--日志文件名称:这里spring.application.name表示工程名称-->
    <springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
    <!--日志文件名称:这里spring.application.name表示工程名称-->
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <!--配置控制台(Console)-->
    <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
    <!--输出到文件-->
    <!-- 时间滚动输出 level为 DEBUG 日志 -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_debug.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 归档的文件名 -->
            <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

  
    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <totalSizeCap>3GB</totalSizeCap>
            <maxFileSize>100MB</maxFileSize>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--Mq消费者日志-->
    <appender name="MQ_RECEIVE_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/mqLog/info.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <FileNamePattern>${log.path}/mqLog/log-info-%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <MaxHistory>15</MaxHistory>
            <maxFileSize>100MB</maxFileSize>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>utf8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

    <!--控制所有的日志级别-->
    <root level="INFO">
        <!-- 将当前日志级别输出到哪个追加器上面 -->
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="DEBUG_FILE"/>
        <appender-ref ref="INFO_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>
    <logger name="com.fairy.mbg.mapper" level="DEBUG"/>
    <logger  name="com.fairy.user" level="ERROR">
        <appender-ref ref="ERROR_LOG"/>
    </logger>


    <logger  name="org.springframework.data.mongodb.core" level="DEBUG">
    </logger>

    <logger  name="org.apache.ibatis" level="DEBUG">
    </logger>
</configuration>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解一下Java的日志体系 的相关文章

  • 在java中将StreamWriter转换为OutputStream?

    我正在尝试使用 System setOut 将 System out 重定向到字符串 它需要一个 PrintStream 有什么方法可以将 StringWriter 转换为 Stream 以便我可以将其传递给 setOut 吗 你不能完全这
  • Android NumberPicker 带字符串

    I have customised the NumberPicker to show text The output is this 当我按 确定 时 我想将 e x 鼠标添加到我的列表 文章 中 我得到的是索引值 int 它由 array
  • 如何使用 SLF4J 和 Log4j2 记录 FATAL(或任何自定义日志级别)

    我有那些具体的要求 需要能够登录FATAL level 需要使用SLF4J 需要使用Log4j2 现在 这是我的执行 final Logger logger LoggerFactory getLogger HelloWorld class
  • V8 如何管理它的堆?

    我知道V8的垃圾收集在工作时 会从GC的root开始追踪 这样无法到达的对象就会被标记然后被清除 我的问题是GC是如何遍历那些对象的 必须有一个数据结构来存储所有可达或不可达的对象 位图 链接表 顺便说一句 JVM 也做同样的事情吗 艾伦秀
  • Spring webflow 应用程序:HTTP 302 暂时移动

    我的 java 应用程序中的每个请求都会生成另外 2 个带有 HTTP 302 错误的请求 例如 如果请求查看名为板 html 这个请求是从首页 html 我收到按以下顺序生成的 3 个请求 POST home html 302 Moved
  • 如何在Spring的applicationContext.xml中指定默认范围来请求范围?

    我想让所有 bean 请求默认作用域 但是 Spring 文档说默认作用域是 Singleton 第 3 4 1 和 3 4 2 节http static springsource org spring docs 2 5 x referen
  • java“void”和“非void”构造函数

    我用 java 编写了这个简单的类 只是为了测试它的一些功能 public class class1 public static Integer value 0 public class1 da public int da class1 v
  • 在气球内显示带有照片的多个地标的最佳做法是什么?

    我有一个项目如下 从手机上拍摄几张照片 将照片保存在网络系统中 然后将照片显示在其中的谷歌地球上 我读过很多文章 但它们都使用 fetchKml 我读过的一篇好文章是使用 php 但使用 fetchKml 我不知道是否可以使用 parseK
  • 删除 servlet 中的 cookie 时出现问题

    我尝试使用以下代码删除 servlet 中的 cookie Cookie minIdCookie null for Cookie c req getCookies if c getName equals iPlanetDirectoryPr
  • firestore快照监听器生命周期和定价之间有什么关系?

    在我的活动中 我有一个字符串列表 这些字符串表示我想要附加快照侦听器的 Firestore 文档 我使用 Acivity ModelView 存储库结构 在活动的 onCreate 中 我向 ViewModelProvider 询问适当的
  • 如何在具有动态列的表中插入值 Jdbc/Mysql

    我想在具有动态列的表中添加值 我设法创建一个包含动态列的表 但我不知道如何插入数据 Create Table sql CREATE TABLE MyDB myTable level INTEGER 255 int columnNumber
  • 无法从后台服务通过 WiFi 访问互联网

    我将直接介绍我发现的一些事实 数据 如果您遇到 解决了类似的问题 请帮助我 我每 5 分钟向服务器发送一次数据 除非用户在服务器的帮助下手动将其关闭 wakeful broadcast receiver通过一个intent service
  • 业务代表与服务定位器

    Business Delegate 和 Service Locator 之间有什么区别 两者都负责封装查找和创建机制 如果 Business Delegate 使用 Service Locator 来隐藏查找和创建机制 那么 Busines
  • 如何模拟一个方面

    我目前正在使用aspectj 开发一些监控工具 因为这个工具应该是技术独立的 尽可能 所以我没有使用 Spring 进行注入 但我希望我的方面能够经过单元测试 方面示例 Aspect public class ClassLoadAspect
  • 独占锁定ConcurrentHashMap

    我知道不可能锁定 ConcurrentHashMap 进行独占访问 但是 我找不到原因 是因为构成CHM的 Segment 没有被api公开吗 据推测 如果是的话 客户端代码可以执行 交接 锁定 Cheers 我知道不可能锁定 Concur
  • getClassLoader().getResource() 返回 null

    我有这个测试应用程序 import java applet import java awt import java net URL public class Test extends Applet public void init URL
  • 您能让 Tomcat 6 stdout.log 文件表现得像 log4j DailyRollingFileAppender 吗?

    我们使用的是 Tomcat 6 的 Windows 安装 默认情况下 我们应用程序的 log4j 输出将转到 catalina base logs stdout log 文件 该日志文件仅在我们重新启动 Tomcat 时滚动 并且文件名始终
  • 如何使用 Java 原生接口从 Java 调用 Go 函数?

    可以通过以下方式调用 C 方法JNA https en wikipedia org wiki Java Native AccessJava 中的接口 如何使用 Go 实现相同的功能 package main import fmt impor
  • Java String.format 向整数添加空格

    我有一小段代码 我不明白输出 此输出向我的字符串格式文本添加空格 我做错了什么吗 public class HelloWorld public static void main String args int a1 540 int a2 4
  • 如何在将数据发送到 Firebase 数据库之前对其进行加密?

    我正在使用 Firebase 实时数据库制作聊天应用程序 我知道 Firebase 非常安全 只要您的规则正确 但我自己可以阅读使用我的应用程序的人的所有聊天记录 我想阻止这种情况 为此我需要一种解密和加密方法 我尝试使用凯撒解密 但失败了

随机推荐

  • python程序设计报告-20191206 实验二《Python程序设计》实验报告

    学号 2019 2020 2 Python程序设计 实验二报告 课程 Python程序设计 班级 1912 姓名 陈发强 学号 20191206 实验教师 王志强 实验日期 2020年4月19日 必修 选修 公选课 1 实验内容 设计并完成
  • 7-7 12-24小时制 (15 分)

    编写一个程序 要求用户输入24小时制的时间 然后显示12小时制的时间 输入格式 输入在一行中给出带有中间的 符号 半角的冒号 的24小时制的时间 如12 34表示12点34分 当小时或分钟数小于10时 均没有前导的零 如5 6表示5点零6分
  • 雷达系统与信号处理概述(一)

    第一章 雷达系统与信号处理概述 一 目录 第一章 雷达系统与信号处理概述 一 1 1 雷达的基本功能 1 2 检测 跟踪 成像概述 1 3 检测概率和虚警概率 1 3 1检测概率 1 3 2虚警概率 1 4 雷达分辨率 1 4 1 雷达距离
  • 静态对象、全局对象与程序的运行机制

    静态对象 全局对象与程序的运行机制 1 在介绍静态对象 全局对象与程序的运行机制之间的关系之前 我们首先看一下atexit函数 atexit函数的声明为 int atexit void cdecl func void 参数为函数指针 返回值
  • vue面试题+答案,2021前端面试

    vue面试题 答案 2022前端面试 前端进阶面试题详细解答 MVC 和 MVVM 区别 MVC MVC 全名是 Model View Controller 是模型 model 视图 view 控制器 controller 的缩写 一种软件
  • 深度学习课程设计——波士顿房价预测

    基于密集连接神经网络的波士顿房价预测 摘 要 神经网络是从信息处理角度对人脑神经元网络进行抽象 建立某种模型 按不同的连接方式组成不同的网络 本文以波士顿房价这一经典数据集为基础 该数据集包含了住宅用地所占比例等13个特征 由于keras
  • rabbitmq基础9——流控、镜像队列、网络分区

    文章目录 一 流控 1 1 流控机制 1 2 流控原理 1 3 流控状态显示 1 4 流控对象 1 5 性能提升 二 镜像队列 2 1 机制原理 2 1 1 集群结构 2 2 镜像结构 2 2 1 组播GM 2 2 1 1 实现原理 2 2
  • 1067 Sort with Swap(0, i) (25 分)

    题目 题目链接 题解 思维 DFS 比较难想的是问题转化的思路 规定a i 表示索引为i处的初始数为a i 我们引入边 由i指向a i 由a i 指向i也可以 将所有n个边都连上后 可能存在若干个环 也可能自己指向了自己 自环 我们思考几种
  • 基于规则的错别字改错

    利用ahocorasick库调用AC自动机寻找已经定义的错别字 不进行分词 并输出错别字开始位置和结束位置 并且在原文中进行改正 import ahocorasick def correct typos text typos 构建 AC 自
  • 字符串排序(函数,指针)(C语言实现)

    编写程序 用户输入n个 n lt 100 字符串 每个字符串长度小于100 按照字典顺序将字符串进行排序 并输出 要求在排序中使用指针数组完成 输入说明 输入第一行是一个整数数字 表示n 接下来有n行字符串 表示待排序字符串 输出说明 输出
  • 虚拟现实期末考试

    考点 考试分比 考试题型单项选择题40 名词解释题10 简答题20 程序设计题8 综合题12 材料分析题10 等 选择题 名词解释 VR 虚拟现实技术 英文名称 Virtual Reality 缩写为VR 是20世纪发展起来的一项全新的实用
  • linux sudo su - 免密配置

    添加用户 sudo useradd d home awen m s bin bash awen 添加用户切换root免密配置 echo awen ALL ALL NOPASSWD ALL gt gt etc sudoers d 90 clo
  • 如何更改电脑开机密码

    以我的电脑为例 是Windows 10系统的笔记本电脑 想要重新设置开机密码 相信大家都有想重新设置密码的冲动 网上也有对应的教程 但是很多人都有一个疑问 为什么根据教程来修改却没有成功 或者是重新登录电脑发现密码根本没有变化 其实不然 这
  • 技术进化对风险隔离与屏蔽超过民众想象

    刷脸支付公众在收获着消费便捷快感的同时 更多地则对刷脸支付的安全性与风险性提出了质疑 与指纹 虹膜等相比 人脸具有弱隐私性的生物特征 而且正是由于手机这一介质的缺失 人脸信息的克隆与利用也会变得 更加容易 相应地 用户使用刷脸支付的风险也就
  • Linux系统卡在iscsi服务导致无法正常开机

    现象 存储网络断开了 机器再开机时卡在开机logo去挂载iscsi 导致没法正常开机 解决办法 1 进救援模式或者单用户模式 将iscsid服务开机自启关了并禁用 关闭自启可能还是存在会被唤醒的情况 systemctl disable is
  • Maven项目的两种打包方式-spring-boot-mavne-plugin/maven-jar-plugin

    Maven项目的两种打包方式 spring boot mavne plugin maven jar plugin 1 前言 Maven的两种打包方式 2 流程图 3 spring boor maven plugin打包 4 maven ja
  • Java架构师的10个学习经验分享,初学者必看

    从零基础学习Java 只要方法正确 依然可以学好Java编程 学习Java就像交朋友一样 要从陌生到熟悉再到铁杆搭档一生相伴的过程 随着深入的了解 你不但会发现学Java并不是和想象的那样无聊和困难 而且还有一些美妙之感 当然在拥有强大的技
  • SecureCRT8.5的下载、安装、注册、连接

    https blog csdn net qq 37233070 article details 120683434
  • 前端Blob文件导出

    前端Blob文件导出 前言 一 Blob是什么 二 axios 拦截器中做统一处理 三 页面全局封装下载组建 总结 前言 通过把blob转file对象的方法下载文件 一 Blob是什么 Blob 对象表示一个不可变 原始数据的类文件对象 B
  • 了解一下Java的日志体系

    目录 了解日子框架体系 分析日志框架如何转换 logback日志的集成 SpringBoot日志使用 常见的一些日志框架如 commons logging jar log4j jar sl4j api jar等 他们之间是存在一定关系的 在