Microservices: Upgrading to Micronaut 2.0

18/08/2020

It is amazing how quickly time passed. It seems that it was yesterday when we started our journey with Micronaut, but we are just about to celebrate the 2nd anniversary of the first commit in our LAB Insurance Sales Portal demo project. Our project demonstrates how you can take advantage of Micronaut’s cool features to build and connect microservices. In this post, we will present our experience with upgrading the project to a just-released version of Micronaut – Micronaut 2.0. We will also discuss what’s new and hot in this version.

But first, some reminders about the functionality and purpose of our project. Insurance Sales Portal is a system that allows insurance agents to log in, offer various insurance products from a catalog, calculate prices, create offers, sell policies, print required documents, search and review sold policies, view various sales statistics, and chat with other agents.

Unnamed - Altkom Software & Consulting

The system uses various data sources: relational databases (H2), document databases (MongoDb), and search engines (Elastic Search). It uses Apache Kafka to connect microservices using event-driven architecture. It also demonstrates how to uses service discovery, distributed tracing, and how to implement HTTP REST-based communication between services using Micronaut’s declarative HttpClient.

If you would like to read a more detailed description, feel free to click – Building Microservices with Micronaut.

Upgrading first microservices

Let’s start upgrading. Our first target is Product Service. This service uses MongoDb and exposed the product catalog via the REST API.

I am not a big fan of messing in the pom.xml files, especially when it comes to major version upgrades. But Micronaut version 2.0 brings a very cool feature that will save me a lot of time. I can now go to micronaut.io/launch and use the user interface to select dependencies, build tool, unit test frameworks, java version, and stuff.

Unnamed - Altkom Software & Consulting

Now I can click the Preview button, see my newly generated project structure, select pom.xml, examine it, and use it as the knowledge source to update pom files in my project.

Unnamed - Altkom Software & Consulting

Micronaut’s Maven support has been greatly enhanced in this version. The first thing we notice is a new parent pom. We are going to use it and add it as a parent project in our pom.xml.

<parent>
        <groupId>io.micronaut</groupId>
        <artifactId>micronaut-parent</artifactId>
        <version>2.0.0</version>
</parent>

We now update the properties section and change Micronaut’s version number:

<properties>
        <micronaut.version>2.0.0</micronaut.version>
        <jdk.version>1.8</jdk.version>
        <maven.compiler.target>${jdk.version}</maven.compiler.target>
        <maven.compiler.source>${jdk.version}</maven.compiler.source>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <exec.mainClass>pl.altkom.asc.lab.micronaut.poc.product.service.ProductApplication</exec.mainClass>
    </properties>

We can get rid of referenced Micronaut’s BOM, which is no longer needed. Now it’s time to look at the dependencies list. It seems that some packages in Micronaut changed Group IDs. One of them is micronaut-mongo-reactive, which was moved from io.micronaut.configuration to io.micronaut.mongodb.

We will also use our upgrade to Micronaut version 2 as an opportunity to upgrade test framework in all our projects to JUnit 5.

In order to do that we replaced all test dependencies previously used with a new list:

<!-- TEST -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.micronaut.test</groupId>
            <artifactId>micronaut-test-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- TEST -->

It seems that we are done with the dependencies list. Now we are going to replace the build section with the one from freshly generated pom for the new 2.0 project. After that, we need to add Lombok to the list of annotation processor paths. It is important to put it before Micronaut processors, so that all constructors, getters/setters generated by Lombok will be available to Micronaut’s bean analyzers.

<build>
        <plugins>
            <plugin>
                <groupId>io.micronaut.build</groupId>
                <artifactId>micronaut-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.7.0</version>
                    <configuration>
                        <source>${jdk.version}</source>
                        <target>${jdk.version}</target>
                        <compilerArgs>
                            <arg>-parameters</arg>
                        </compilerArgs>
                        <annotationProcessorPaths>
                            <path>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                                <version>1.18.0</version>
                            </path>
                            <path>
                                <groupId>io.micronaut</groupId>
                                <artifactId>micronaut-inject-java</artifactId>
                                <version>${micronaut.version}</version>
                            </path>
                            <path>
                                <groupId>io.micronaut</groupId>
                                <artifactId>micronaut-validation</artifactId>
                                <version>${micronaut.version}</version>
                            </path>
                        </annotationProcessorPaths>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

With this change, we are ready to build, test, and run our first Micronaut 2.0 based microservices. Micronaut team claims that this new version improves already great startup performance. Let’s check this out.

Product serviceMicronaut 1.3Micronaut 2.0
Startup time1651 ms1194 ms
Amazing!!! 28% startup performance improvement.

The last thing to add here is a new Micronaut Maven’s plugin. With it, we can:

mvn mn:run

This command will build and run our project. It will also watch for changes in our source code, and when they are detected, it will rebuild and restart the application, which combined with incredible startup times gives us fantastic developers’ experience. We no longer how to stop, build, and start our app.

Upgrading service with JPA and transactions

Let’s tackle a slightly more complex task. The next service we will upgrade is Pricing Service. It is responsible for an insurance price calculation. It uses JPA (Hibernate), Spring transactions, and Micronaut Data access toolkit.

With Micronaut 2 we no longer have to use spring managed transactions. In fact, it is recommended not to use it and instead use Micronaut-based transaction management. To achieve this instead of using io.micronaut.spring.tx.annotation.Transactional we use JEE javax.transaction.Transactional. If you need a read-only transaction, you have to use Micronaut @Readonly annotation instead of Spring’s @Transactional(readonly=true).

@ReadOnly
    public CalculatePriceResult handle(CalculatePriceCommand calculatePriceCommand) {
        Tariff tariff = tariffs.getByCode(calculatePriceCommand.getProductCode());
        Calculation calculation = tariff.calculatePrice(toCalculation(calculatePriceCommand));
        return resultFromCalculation(calculation);
    }

This means that we can get rid of all Spring related dependencies from our pom.xml file.

<!-- spring managed tx -->
        <dependency>
            <groupId>io.micronaut</groupId>
            <artifactId>micronaut-spring</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micronaut.data</groupId>
            <artifactId>micronaut-data-spring</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>

We also have to update GroupId for micronaut-jdbc-hikari, which is now io.micronaut.sql.

Of course, we have to repeat changes common to all projects that we are going to upgrade: add parent Micronaut project, remove BOM reference, update properties, and build sections.

There is one last thing we should. Official Micronaut’s documentation tells us that since 2.0 we should mark blocking code with @ExecuteOn annotation specifying a thread pool that our blocking code should be executed on. If we forget to do this, no warning or exception will be thrown but you can expect performance degradation if threads in the request processing pool will be blocked.

As our service uses JPA which is blocking communication, we most definitely should modify our controller to tell specify thread pool to use for blocking communications.

@ExecuteOn(TaskExecutors.IO)
    @Override
    public CalculatePriceResult calculatePrice(CalculatePriceCommand cmd) {
        return calculatePriceHandler.handle(cmd);
    }
}

With that change, we are good to go. Let’s build and run our service.

Pricing serviceMicronaut 1.3Micronaut 2.0
Startup time3626 ms2905ms
Again – incredible improvement – 20% faster!!!

Upgrading the rest of the pack

We continue by modifying pom files for all other services. We apply the same schema – add parent pom, remove BOM reference, update properties, update build section (not forgetting to handle Lombok case).

In some services, we have to adjust GroupIds for packages that were moved. For example Kafka dependency changed from io.micronaut.configuration:micronaut-kafka to io.micronaut.kafka:micronaut-kafka fo Policy Service and Policy Search Service.

Also, Netflix Hystrix dependency has been moved. We had to update Payment Service pom file.

BEFORE: 
      <dependency>
            <groupId>io.micronaut.configuration</groupId>
            <artifactId>micronaut-netflix-hystrix</artifactId>
            <scope>compile</scope>
        </dependency>

AFTER:
       <dependency>
            <groupId>io.micronaut.netflix</groupId>
            <artifactId>micronaut-netflix-hystrix</artifactId>
            <scope>compile</scope>
        </dependency>

With this work done, we can check how startup times changed for these services.

Startup time:Micronaut 1.3Micronaut 2.0
Policy service3088ms2246ms
Policy Search service1802ms1413ms
Payment service3655ms2730ms

Upgrading security service

There are some breaking changes in Micronaut Security 2.0. Let’s see what we had to do, to upgrade our Auth Service which is responsible for handling authentication and producing JWT tokens with user claims.

The first thing we needed it to adjust micronaut-jdbc-hikari and micronaut-security-jwt groupIds.

BEFORE:
           <dependency>
            <groupId>io.micronaut.configuration</groupId>
            <artifactId>micronaut-jdbc-hikari</artifactId>
            <scope>runtime</scope>
        </dependency>

AFTER:
        <dependency>
            <groupId>io.micronaut.sql</groupId>
            <artifactId>micronaut-jdbc-hikari</artifactId>
            <scope>runtime</scope>
        </dependency>
BEFORE:
        <dependency>
            <groupId>io.micronaut</groupId>
            <artifactId>micronaut-security-jwt</artifactId>
            <scope>compile</scope>
        </dependency>

AFTER:
         <dependency>
            <groupId>io.micronaut.security</groupId>
            <artifactId>micronaut-security-jwt</artifactId>
            <scope>compile</scope>
        </dependency>

The main Interface for authentication implementation – AuthenticationProvider – has changed. Actually, its only method authenticate parameters have changed.

In the previous version this method looked like this:

Publisher<AuthenticationResponse> authenticate(AuthenticationRequest request)

And was changed into:

Publisher<AuthenticationResponse> authenticate(HttpRequest<?> httpRequest, AuthenticationRequest<?, ?> authenticationRequest)

Username and password are now provided through authenticationRequest parameter. So we need to change our code a little:

Optional<InsuranceAgent> agent = insuranceAgents.findByLogin((String)authenticationRequest.getIdentity());

if (agent.isPresent() && agent.get().passwordMatches((String) authenticationRequest.getSecret())) {
return Flowable.just(createUserDetails(agent.get()));
}

We also have to update application.yaml because in 2.0 security module uses different configuration properties.

We have to replace old configuration:

security:
    enabled: true
    endpoints:
      login:
        enabled: true
      oauth:
        enabled: true
    token:
      jwt:
        enabled: true
        generator:
          access-token-expiration: 86400
        signatures:
          secret:
            generator:
              secret: pleaseChangeThisSecretForANewOne

With a new one:

security:
    authentication: bearer
    token:
      jwt:
        generator:
          access-token:
            expiration: 86400
        signatures:
          secret:
            generator:
              secret: pleaseChangeThisSecretForANewOne

Refresh tokens are by default not generated. We have to adjust our test to expect null values in refresh tokens.

Now we are ready to build and run our Auth service.

Auth ServiceMicronaut 1.3Micronaut 2.0
Startup time1645ms1306ms

The last step is to upgrade our API gateway. This task is pretty simple as only GroupIds for micronaut-security-jwt.

That’s it my friends. We upgraded our whole solution to Micronaut 2.0!

Micronaut 2.0 New Features Summary

Let’s quickly summarize what is new in the Micronaut 2.0 version:

And many other small changes that are listed here.

Links

Wojciech Suwała
Head Architect, Altkom Software & Consulting

Speed of feature delivery is the key property of microservice-based architectures. We use this architectural style to deliver solutions faster […]
To 1.1.0.M1 version Micronaut did not have integration with RabbitMQ. We could use libraries that enabled integration with Apache Kafka […]
It’s been almost a year since our first blog post about Micronaut. We saw a big potential of this new […]

Zarejestruj się na webinar:

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych dla potrzeb procesu realizacji zgłoszenia (pokaż więcej) przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa), zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”). Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne, ale konieczne do obsługi zgłoszenia oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych w celach marketingowych (pokaż więcej)przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa)oraz otrzymywanie informacji handlowych drogą elektroniczną na adres e-mail i numer telefonu podany przeze mnie, zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”), oraz Ustawy z dnia 18 lipca 2002 r. o świadczeniu usług drogą elektroniczną. Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

 

Watch for free

Enter your contact details to receive a link to the recording:

I voluntarily consent to the processing of my personal data for the purposes of the application process (show more) by Altkom Experts sp. z o.o. and Altkom Software & Consulting sp. z o.o. (51 Chłodna Street, 00-867 Warsaw), in accordance with Regulation 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of individuals with regard to the processing of personal data and on the free movement of such data ("RoDO"). I am aware that providing the above personal data is voluntary, but necessary to handle the request, and that I have the right to access the content of my data and the possibility of correcting it, and that my consent may be revoked at any time. Please contact the Altkom Data Protection Officer: iodo@altkom.pl.

I voluntarily consent to the processing of my personal data for marketing purposes (show more)by Altkom Experts sp. z o.o. and Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warsaw) and receiving commercial information by electronic means to the e-mail address and telephone number provided by me, in accordance with Regulation 2016/679 of the European Parliament and of the Council of 27 April 2016 on the protection of individuals with regard to the processing of personal data and on the free movement of such data ("RODO"), and the Act of 18 July 2002 on the provision of electronic services. I am aware that providing the above personal data is voluntary and that I have the right to access and correct my data and that my consent may be revoked at any time. Please contact the Altkom Data Protection Officer: iodo@altkom.pl.

 

Zarejestruj się na webinar:

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych dla potrzeb procesu realizacji zgłoszenia (pokaż więcej) przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa), zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”). Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne, ale konieczne do obsługi zgłoszenia oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych w celach marketingowych (pokaż więcej)przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa)oraz otrzymywanie informacji handlowych drogą elektroniczną na adres e-mail i numer telefonu podany przeze mnie, zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”), oraz Ustawy z dnia 18 lipca 2002 r. o świadczeniu usług drogą elektroniczną. Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

 

Zarejestruj się na webinar:

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych dla potrzeb procesu realizacji zgłoszenia (pokaż więcej) przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa), zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”). Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne, ale konieczne do obsługi zgłoszenia oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych w celach marketingowych (pokaż więcej)przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa)oraz otrzymywanie informacji handlowych drogą elektroniczną na adres e-mail i numer telefonu podany przeze mnie, zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”), oraz Ustawy z dnia 18 lipca 2002 r. o świadczeniu usług drogą elektroniczną. Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

 

Zarejestruj się na webinar:

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych dla potrzeb procesu realizacji zgłoszenia (pokaż więcej) przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa), zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”). Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne, ale konieczne do obsługi zgłoszenia oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl

Wyrażam dobrowolnie zgodę na przetwarzanie moich danych osobowych w celach marketingowych (pokaż więcej)przez Altkom Experts sp. z o.o. oraz Altkom Software & Consulting sp. z o.o. (ul. Chłodna 51, 00-867 Warszawa)oraz otrzymywanie informacji handlowych drogą elektroniczną na adres e-mail i numer telefonu podany przeze mnie, zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych („RODO”), oraz Ustawy z dnia 18 lipca 2002 r. o świadczeniu usług drogą elektroniczną. Mam świadomość, iż podanie powyższych danych osobowych jest dobrowolne oraz że posiadam prawo dostępu do treści swoich danych i możliwość ich poprawiania a zgoda może być odwołana w każdym czasie. Kontakt do inspektora ochrony danych osobowych w Altkom: iodo@altkom.pl