Java socket中关闭IO流后,发生啥事
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java socket中关闭IO流后,发生啥事相关的知识,希望对你有一定的参考价值。
参考技术A 为了方便讲解,我们把DataOutputstream dout = new DataOutputStream(new BufferedOutputStream(mySocket.getOutputStream()));中的dout做为Socket输出流的代言。同 样的,din是输入流的代言。可以造成dout被关闭的操作有:
1、调用dout.close();或din.close();因为使用这种流关闭,会造成socket被关闭,所以输入输出流都将不可再用。
2、调用socket.close();
3、调用socket.shutdownOutputStream();单方面关闭dout,此时din还可正常使用。
以下,我将对socket中关闭输出流进行3个测试:
输出流关闭测试一:socket关闭吗?
输出流关闭测试二:该流是否可以重新开启?
输出流关闭测试三:输出缓冲区里的数据是丢弃,还是发送?
测试结果如下:
测试一:dout.close();会造成socket被关闭,但socket.shutdownOutputStream()不会。
测试二:不可以,会抛出异常!
测试三:丢弃
转载
如何在 gradle 启动测试中关闭关闭挂钩的输出?
【中文标题】如何在 gradle 启动测试中关闭关闭挂钩的输出?【英文标题】:How to turn off output from shutdown hooks in gradle boot tests? 【发布时间】:2020-05-18 00:08:07 【问题描述】:你可以从https://start.spring.io/starter.zip?type=gradle-project&language=java&bootVersion=2.2.5.RELEASE&baseDir=demo&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&packaging=jar&javaVersion=1.8&dependencies=h2,data-jpa,web这个issue从start.spring.io生成一个项目
我有一个用 gradle 构建的多模块 springBoot 应用程序,有一堆 SpringBoot 集成测试。当我进行构建时,我最终会得到一些从 SpringBoot 关闭到控制台的输出,如下所示。如何关闭此输出?
± |master ↑1 1 S:3 U:10 ✗| → ./gradlew build
> Task :core:test
2020-02-01 11:20:33.529 INFO 24114 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-02-01 11:20:33.531 INFO 24114 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2020-02-01 11:20:33.538 INFO 24114 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
> Task :email:test
2020-02-01 11:20:43.820 INFO 24150 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-02-01 11:20:43.820 INFO 24150 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-02-01 11:20:43.822 INFO 24150 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Shutdown initiated...
2020-02-01 11:20:43.822 INFO 24150 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2020-02-01 11:20:43.830 INFO 24150 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
2020-02-01 11:20:43.830 INFO 24150 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Shutdown completed.
> Task :security:test
2020-02-01 11:20:54.941 INFO 24188 --- [extShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-02-01 11:20:54.944 INFO 24188 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2020-02-01 11:20:54.952 INFO 24188 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.1.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 46s
57 actionable tasks: 54 executed, 3 up-to-date
作为参考,使用 gradle 从 start.spring.io 创建的应用程序不会在屏幕上产生任何输出
./gradlew build
BUILD SUCCESSFUL in 779ms
5 actionable tasks: 5 up-to-date
而是将输出放在build/reports/
在我的情况下,我没有对引导附带的日志记录配置进行任何更改。没有 logback.xml,或对日志级别的 application.yml 进行更改。我期待 gradle 正在捕获系统输出和系统错误并将它们发送到build/reports/
,但一些输出似乎正在逃逸到系统输出。
【问题讨论】:
将这些包或类的日志级别调整为低于INFO
(或完全删除)。
这些是INFO
级别的日志行。如您所见,它们源自关闭挂钩,并且它们最终出现在配置日志记录的位置。我想从理论上讲,由于日志记录配置的更改以及随后异步执行的钩子,消息可能最终出现在与预期不同的位置。所以它会将这些行默认到控制台,因为之前的配置已被卸载。也许吧。
你能添加你的测试类,以及你的主应用程序类吗?以及任何与数据源配置相关的 application.properties/yml?
可能是关闭挂钩发生在 Gradle 测试工作进程在其输出重定向被拆除后被关闭时。这可能值得一个 gradle/gradle 问题来开启讨论。
理想情况下,spring boot 在您的测试中是关闭的,而不必依赖 jvm 关闭挂钩,这将是一个 spring 问题。
【参考方案1】:
@eskatos 是对的。在关闭工作进程之前执行测试用例后,日志管理器被拆除。当工作进程关闭并重定向回控制台时,将执行所有关闭挂钩。
由于这些消息是由 spring boot 生成的,最好的地方是使用 logback 测试配置 xml 过滤关闭消息。
src/test/resources 中类似于 logback-test.xml 的东西
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return event.getThreadName().contains("ShutdownHook");</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<encoder>
<pattern>%dHH:mm:ss.SSS [%thread] %-5level %logger36 - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
build.gradle
testCompile 'org.codehaus.janino:janino'
【讨论】:
【参考方案2】:可以使用TestLoggingContainer
testLogging.showStandardStreams = false
禁用输出 或 决定在Test
任务中记录onOutput
的内容,以控制测试JVM 的stdout/stderr:
apply plugin: 'java'
test
// show standard out and standard error of the test JVM on the console
// can be used to disable the console output:
testLogging.showStandardStreams = true
// listen to standard out and standard error of the test JVM
// can be used to make the logging optional:
onOutput descriptor, event ->
logger.lifecycle("Test: " + descriptor + " produced standard out/err: " + event.message)
这些流是来自 JVM 的 TestLogEvent
STANDARD_OUT
和 STANDARD_ERROR
。当可以确定包含extShutdownHook
的event.message
时,可以跳过日志记录。
【讨论】:
见start.spring.io/…可以从start.spring.io生成一个项目到这个issue来重现这个issue 这可能不是问题,因为INFO
是 Spring 的默认日志记录级别;可以设置其他日志级别,例如。 logging.level.org.springframework=TRACE
作为环境变量。
我相信关闭挂钩日志是在测试任务之外生成的。您能否更新您的答案以显示如何过滤关闭挂钩消息?我认为过滤这些消息的最佳位置是它们在 Spring Boot 中的生成位置。【参考方案3】:
我可以隐藏 spring-data 特定的测试记录(基于this spring-starter)
通过将以下application.properties
添加到 src/test/resources:
logging.level.root=ERROR
logging.level.org.springframework
不会影响例如com.zaxxer.hikari
记录器,但你在这里有 flexible options。
(root=ERROR
就像“大锤方法”)。
(src/main/resources
也是可能的,但不仅在测试时有效,而且在应用程序运行时也有效)
(application.properties
只是此属性的 many possible "locations" 之一...另请参阅:https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html)
有了这个,我得到一个“静默”的 gradle 输出,也在 clean build
:
$ ./gradlew clean build
BUILD SUCCESSFUL in 10s
7 actionable tasks: 7 executed
【讨论】:
【参考方案4】:Gradle 有一个安静模式。
./gradlew build -q
但您仍然需要有关测试的信息。你可以使用 jacoco 和 sonarqube。它对我有用 here 和 here。
【讨论】:
【参考方案5】:Spring Boot 2.5 更新
此解决方案不再有效。 有关详细信息,请参阅此 GitHub 问题:https://github.com/spring-projects/spring-boot/issues/28108
在最近的版本中,Spring Boot 具有在退出之前关闭日志系统的属性。将以下行添加到您的配置中:
src/test/resources/application.yaml
logging:
register-shutdown-hook: true
src/test/resources/application.properties
logging.register-shutdown-hook=true
属性定义和文档可以在 GitHub 上的 Spring Boot 存储库中找到:https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json
"name": "logging.register-shutdown-hook",
"type": "java.lang.Boolean",
"description": "Register a shutdown hook for the logging system when it is initialized. Disabled automatically when deployed as a war file.",
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
"defaultValue": true
运行测试时似乎默认未注册关闭挂钩。
【讨论】:
以上是关于Java socket中关闭IO流后,发生啥事的主要内容,如果未能解决你的问题,请参考以下文章