One thing I have always loved about coding is the DRY principle. I want to reduce tasks/features down to their simplest form and then make them reusable to others. Another thing I love is creating libraries that are easy to adopt and require little configuration to use. This article combines both these concepts and a little bit more.
Prerequisites
Java 8 (depending on where you will use this dependency, you could use a higher version)Maven 3.8.5 (lower versions would probably work as well)
Problem to Solve
I’ve got a new library that I want to use, but it depends on context/state that is thread specific. This is all well and fine until I am forced to go off-thread for some reason. This could be required for many different reasons. Maybe you are using Hystrix, which uses a thread pool by default and you don’t want to use a SEMAPHORE. Maybe you have some asynchronous processing to speed up throughput. Maybe you are managing your own thread-pool via an ExecutorService. Whatever the reasons are, we need to create a way to transfer state from one thread to another and to clean it up after we are done so that shared threads don’t get data from other flows.
Creating a Parent Pom
I’m using Maven to help with dependency management, but you could easily use Gradle or something else. I like to follow the syntax of using the name of the repo/main artifact and then adding .parent . The packaging needs to be pom as this pom.xml is an aggregator for a multi-module set up and doesn’t actually create an artifact that people will use as part of this shared library.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ai.prama.utils</groupId>
<artifactId>state-transfer.parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
...
</project>
Add a modules section and module entries for submodules that we will be creating.
<modules>
<module>api</module>
<module>starters</module>
<module>state-transfer</module>
</modules>
Add any desired properties. I am setting source and target to be java 8 so that my library is accessible to more folks that haven’t switched to newer versions of java yet.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
I’m a strong advocate of dependency management, so add all your main dependency versions.
Note: I am adding local module dependency versions here so that I don’t have to include dependency versions later in child poms.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>ai.prama.utils</groupId>
<artifactId>state-transfer.api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ai.prama.utils</groupId>
<artifactId>state-transfer</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.6</version>
</dependency>
</dependencies>
</dependencyManagement>
API
I want to start out with an API module so that the utility is more extensible if someone wants to override default implementations with their own, but still likes the library in general. This might be overkill for a small project such as this, but it is a good thought processing habit to consider. The module’s pom file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ai.prama.utils</groupId>
<artifactId>state-transfer.parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>state-transfer.api</artifactId>
</project>
In this module, I am creating the following classes: