Deployment

This section covers the deployment of Jmix applications. We will consider basic principles and a few concrete scenarios.

The typical Jmix deployment configuration consists of the following components:

  • The application itself.

  • A relational database.

  • Reverse Proxy (optional).

As any Spring Boot application, a Jmix application can be built and deployed as an executable JAR, WAR, or as a Docker image.

All console commands are relative to the project root.

Creating Executable JAR

In Jmix Studio, open the Gradle tool window and double-click Tasks → build → bootJar.

In the command line, use the following command:

./gradlew bootJar

The executable JAR name will consist of the name and the version of your project. For example, if you specified the following in your settings.gradle:

rootProject.name = 'myapp'

and in your build.gradle:

group = 'com.company'
version = '0.0.1-SNAPSHOT'

then the JAR name will be myapp-0.0.1-SNAPSHOT.jar.

The executable JAR file is created in the /build/libs folder. You can copy it anywhere and run as follows:

java -jar myapp-0.0.1-SNAPSHOT.jar

If you want to customize the packaging process or create a deployable WAR file, refer to the Spring Boot Documentation.

Creating Docker Image

In Jmix Studio, open the Gradle tool window and double-click Tasks → build → bootBuildImage task.

In the command line, use the following command:

./gradlew bootBuildImage

By default, the image will be created with the name of your project and tag which is equal to you project’s version.

For example, if you specified the following in your settings.gradle:

rootProject.name = 'myapp'

and in your build.gradle:

group = 'com.company'
version = '0.0.1-SNAPSHOT'

then the created image will be myapp:0.0.1-SNAPSHOT.

You can find more information on image generation and customization in the Spring Boot Documentation.

Deploying WAR

If you want to build a WAR file for deployment to an application server, follow these steps:

  1. Make sure your main application class extends SpringBootServletInitializer, for example:

    @SpringBootApplication
    public class MyApplication extends SpringBootServletInitializer {
        // ...
    }
  2. Add the war plugin to the plugins section of your build.gradle file:

    plugins {
        // ...
        id 'war'
    }
  3. Reload Gradle project either by clicking Load Gradle Changes button in a popup at the right side of the editor window or clicking Reload All Gradle Projects in the Gradle tool window.

  4. Open the Gradle tool window and double-click Tasks → build → bootWar, or use the following command:

    ./gradlew bootWar

The WAR file is created in the /build/libs folder. The file name is generated as described in the previous section.

You will not be able to run Jmix applications on Tomcat 10 because it does not support Java EE 8 (javax.* namespace) and requires Jakarta EE 9 (jakarta.*), see Tomcat documentation for details. Use the latest Tomcat 9 to deploy Jmix WAR.

Using JNDI Data Source

When deploying your application as a WAR, you can use a JNDI data source provided by the application server to externalize connection settings.

See below how to configure the main DataSource of your application for development and production environments using the Spring’s profiles feature.

  1. In your main application class, add @Profile("!prod") annotation to dataSourceProperties and dataSource methods to make sure these beans are created only in development environment:

    @Profile("!prod")
    @Bean
    @Primary
    @ConfigurationProperties("main.datasource")
    DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }
    
    @Profile("!prod")
    @Bean
    @Primary
    @ConfigurationProperties("main.datasource.hikari")
    DataSource dataSource(DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }
  2. Add a method creating a DataSource bean for the production environment:

    @Profile("prod")
    @Bean(name = "dataSource")
    @Primary
    DataSource prodDataSource(ApplicationContext context) {
        JndiDataSourceLookup lookup = new JndiDataSourceLookup();
        DataSource dataSource = lookup.getDataSource("java:comp/env/jdbc/demo"); (1)
    
        // to avoid org.springframework.jmx.export.UnableToRegisterMBeanException:
        for (MBeanExporter mbeanExporter : context.getBeansOfType(MBeanExporter.class).values()) {
            if (JmxUtils.isMBean(((Object) dataSource).getClass())) {
                mbeanExporter.addExcludedBean("dataSource");
            }
        }
    
        return dataSource;
    }
    1 JNDI name of the data source provided by the application server.
  3. When running the application server, set active profile to prod in spring.profiles.active application property.

Below is an example of configuring Tomcat 9 for deploying a demo.war application.

  1. Copy demo.war to tomcat/webapps folder.

  2. Create tomcat/bin/setenv.sh file with the following content:

    CATALINA_OPTS="-Dspring.profiles.active=prod"
  3. Create tomcat/conf/Catalina/localhost/demo.xml file defining the data source and set appropriate database connection parameters:

    <Context>
        <Resource type="javax.sql.DataSource"
                  name="jdbc/demo"
                  driverClassName="org.postgresql.Driver"
                  url="jdbc:postgresql://localhost/demo"
                  username="root"
                  password="root"
                  maxIdle="2"
                  maxTotal="20"
                  maxWaitMillis="5000"
        />
    </Context>

    Notice that the name attribute of the Resource element defines the JNDI name used in the JndiDataSourceLookup.getDataSource() method when creating the DataSource bean.

  4. Copy an appropriate JDBC driver file (for example, postgresql-42.2.9.jar) to tomcat/lib.

When you start Tomcat, the application will use the data source defined in the tomcat/conf/Catalina/localhost/demo.xml file.