DEV Community

Cover image for Develop your Tomcat App with Docker Compose Watch
Ulrich VACHON
Ulrich VACHON

Posted on

Develop your Tomcat App with Docker Compose Watch

Today we will see how Build, Run, Deploy and Modify in immediate mode a simple Java App deployed on Tomcat via the Docker Compose Watch feature.

The purpose of this article is not to introduce the development of some Tomcat App via Spring or whatever platform but instead of that to explain how we can use the Docker's tools to make easier it.

💡A Docker Compose stack is ready to run on my github.com/ulrich space available in the repository : https://github.com/ulrich/develop-java-app-with-compose-watch

Docker Compose Watch in few words

This tool has been released in the Docker Compose v2.22.0 by my favorite ❤️ team at Docker. Quickly when you use Compose during your developments, it can useful to synchronize your local changes with your deployed App running in his container. Before the Watch feature you were forced to use a workaround like Bind mount for getting a hot reloaded capability and it was OK. But in many cases in many technologies, it's not a good idea to work like this because for example in Java (in particular Java WAR App based model) technology, we don't want to deploy our App after a simple modification. You understood, a Java WAR App needs many resources which can slow down the inner loop development experience.

Docker Compose Watch offers an another approach for developers by using of new properties allowing to synchronize with a fine-grained level each piece of your App. By the way, a couple of new commands (develop/watch/action) will help you to define what/when/how I have to synchronize one piece of code (file, directory, module...).

You will find more information in the following source here.

Craft a simple Java WAR App

Add a simple Spring Boot app with the convenience dependencies.

The best way, for generating a ready-to-run application in Java you can use the Spring Boot Initializr tool.

We will need to enroll the following dependencies:

  • spring-boot-starter-tomcat
  • spring-boot-starter-web
  • spring-boot-starter-thymeleaf
  • spring-boot-starter-data-jpa

These followings for this introduction will use Java 21 and Maven.

There is nothing of special to be noted for this application which use the classic architecture from Java App. The data layer is fed by a pre-initialized Postgres Compose service.

After running the Docker Compose services you will access to the students.html page from the following URL : http://localhost:8080/app-for-compose-watch-0.0.1-SNAPSHOT/students/all (figure 1)

Image description

Fig. 1

Run the App with --watch flag

In this introduction, we will see two ways to synchronize our application.

For running the App with the Compose Watch enabled, we have to launch like this :

❯ docker compose up --build --watch
Enter fullscreen mode Exit fullscreen mode

This command will build and run the App with the Compose Watch observer enabled (figure 2).

Image description

Fig. 2

👋 This way to start the services is interesting because in this case, we ask to build, run and watch the expected service with the logs enabled in the console.

 When I want to create or modify the Java code

In Java WAR App based on Tomcat, the easiest way to test the inner-loop development is to instruct Compose Watch for rebuilding and deploying the App when a "witness" file has changed. The following Compose configuration allows this development round-trip :

  app:
    image: app:latest
    build: ./
    develop:
      watch:
        - action: rebuild
          path: deploy.watch
    ports:
      - 8080:8080
Enter fullscreen mode Exit fullscreen mode

The notable point to consider there is the path instruction used to trigger a rebuild action when the developer considers it. As I explained previously, we don't want to trigger a rebuild action for each Java file modifications, so we can consider that when we want to test our modifications, the developer have to update this spy file.

For my part I use a IntelliJ Shell script which update the deploy.watch file located in the root path with this kind of configuration (figure 3).

Image description

Fig. 3

When the Deploy App command is triggered, we can see the Docker Compose Watch feature take the hand and making the expected actions (build, deploy and restart Tomcat). PTAL the following sample of logs after executing the command (figure 4).

Image description

Fig. 4

Practical and inexpensive!

Image description

 When I want to modify a HTML file

The solution to synchronize not compiled sources like Thymeleaf files (for example) is to use the sync action. When we use this feature the Docker Compose doesn't restart the App but only copy and past the files denoted by the couple path/targer. Let's take a look of the following configuration used to (hot) update the students.html file located in src/main/resources/templates/ path.

  app:
    image: app:latest
    build: ./
    develop:
      watch:
        - action: rebuild
          path: deploy.watch
        - action: sync
          path: src/main/resources/templates/
          target: /usr/local/tomcat/webapps/app-for-compose-watch-0.0.1-SNAPSHOT/WEB-INF/classes/templates/
    ports:
      - 8080:8080
Enter fullscreen mode Exit fullscreen mode

The main difference with the previous declaration is the necessity to declare a target path.

Please take a look to the following resource : /students/adults (figure 5).

Image description

Fig. 5

If I modify the template by adding some information, the modification should instantly happened (figure 6).

Image description

Fig. 6

Image description

Fig. 7

 Conclusion

Finally we can consider the Docker Compose Watch tool while developing a Java WAR App on Tomcat. Given that I think is a good alternative from the classical development stack like IntelliJ Plugin or others. All parts of the inner-loop developments can be make in the image itself and no need to install third party tooling.

Have a good day.

Image par jacqueline macou de Pixabay

Top comments (3)

Collapse
 
cavo789 profile image
Christophe Avonture

I've read about --watch months ago and didn't see his added value for me, perhaps can you give me a clue : I'm coding with php, js, css and also bash i.e. don't need any kind of generation.

So, since years, I'm using shared volumes between my host and the container and it's fine.

When I need to deploy my docker image, then I build one. My dockerfile has been created with multistages in mind and allow to choice which target I want (prod or dev). Depending on the target, I have a COPY verb or not.

So, in my use case, do you see a path where --watch can be useful to me ?

Thanks !

Collapse
 
ulrich profile image
Ulrich VACHON

Hello @cavo789 from my point of view, the bind mount feature is for me a "hack" which wasn't planed at origin for the development round-trip. The watch command (flag) is by design dedicated to the development process. Indeed, with the watch command you have a fine-grained control of files synchronization btw the local system and the container. An another interesting point for my usage (Tomcat + Java) is I can control the level of action required. For example when a class file is modified I need to sync+restart the Tomcat server. Unlike, when I modified a HTML file I just need to sync the file.
For terminating, I don't have very accurate information about the subject but underlying we can hope having better performance during a sync file with watch command (use inotify) because the IOs aren't managed in the same way from the bind mount.

Collapse
 
cavo789 profile image
Christophe Avonture

Thanks @ulrich for the reply.