Quick start
January 25, 2023 ยท View on GitHub
Getting it
Download it from repo.spring.io or Maven Central repositories (stable releases only):
repositories {
mavenCentral()
// maven { url 'https://repo.spring.io/milestone' }
// maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
testImplementation 'io.projectreactor.tools:blockhound:$LATEST_RELEASE'
// testImplementation 'io.projectreactor.tools:blockhound:$LATEST_MILESTONE'
// testImplementation 'io.projectreactor.tools:blockhound:$LATEST_SNAPSHOT'
}
Where:
$LATEST_RELEASE | |
$LATEST_MILESTONE | |
$LATEST_SNAPSHOT |
JDK13+ support
for JDK 13+, it is no longer allowed redefining native methods. So for the moment, as a temporary work around, please use the
-XX:+AllowRedefinitionToAddDeleteMethods jvm argument:
Maven
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<argLine>-XX:+AllowRedefinitionToAddDeleteMethods</argLine>
</configuration>
</plugin>
Gradle
tasks.withType(Test).all {
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) {
jvmArgs += [
"-XX:+AllowRedefinitionToAddDeleteMethods"
]
}
}
Using Tomcat
When using BlockHound from a Tomcat webapp, do not embedd blockhound dependency within your webapp. Instead of that, just drop
the blockhound jar in the Tomcat shared "lib" directory.
If you are using Cargo maven plugin, this can be done using a shared classpath
Here is an example using Cargo maven plugin:
<dependencies>
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound</artifactId>
<version>(latest blockhound version)</version>
<scope>provided</scope>
</dependency>
...
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven3-plugin</artifactId>
<version>1.10.4</version>
<configuration>
<container>
<containerId>tomcat9x</containerId>
<type>embedded</type>
<dependencies>
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound</artifactId>
<classpath>shared</classpath>
</dependency>
</dependencies>
</container>
<deployables>
<deployable>
<type>war</type>
<location>${project.build.directory}/${project.build.finalName}.war</location>
<properties>
<context>/</context>
</properties>
</deployable>
</deployables>
</configuration>
</plugin>
</plugins>
</build>
...
Installation
BlockHound is a JVM agent. You need to "install" it before it starts detecting the issues:
BlockHound.install();
On install, it will discover all known integrations (see writing custom integrations for details) and perform a one time instrumentation (see how it works). The method is idempotent, you can call it multiple times.
The best place to put this line is before any code gets executed, e.g. @BeforeClass, or static {} block, or test listener.
BlockHound also supports some testing frameworks.
NB: it is highly recommended to add a dummy test with a well-known blocking call to ensure that it installed correctly.
Something like this will work:
Mono.delay(Duration.ofMillis(1))
.doOnNext(it -> {
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
})
.block(); // should throw an exception about Thread.sleep
If you can't change the application code, you can also activate BlockHound using the -javaagent:
java -javaagent:BlockHound/agent/build/libs/agent.jar -jar my-application.jar
Notice that when using JPMS, for the moment BlockHound needs to be installed using -javaavant JVM option.
What's Next?
You can further customize Blockhound's behavior, see customization.