Micronaut

Vladimír Oraný

Test Facilitator @ Agorapulse

@musketyr

 

http://micronaut.io/

 

Micronaut

menší už to nebude

Micronaut

nic nového pod sluncem

menší už to nebude

Micronaut CLI

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install micronaut
mn create-app cz.jopenspace.conference
cd conference
mn create-bean conference-service
mn create-job summary

DI / IoC

import io.micronaut.context.annotation.Requires;
import io.micronaut.context.annotation.Value;

import javax.inject.Named;
import javax.inject.Singleton;

@Singleton
@Requires(env = "attendees.max")
class ConferenceService {

    private final VenueService venueService;
    private final AttendeeService attendeeService;
    private final int maxAttendees;

    ConferenceService(
            VenueService venueService,
            @Named("jOpenSpace") AttendeeService attendeeService,
            @Value("attendees.max") int maxAttendees
    ) {
        this.venueService = venueService;
        this.attendeeService = attendeeService;
        this.maxAttendees = maxAttendees;
    }

}

Job

import javax.inject.Singleton;
import io.micronaut.scheduling.annotation.Scheduled;

@Singleton
public class SummaryJob {

    @Scheduled(fixedRate = "5m")
    public void process() {}
}

Zase další framework?

DI / IoC + AoT

  • $ConferenceServiceDefinition.class
  • $ConferenceServiceDefinitionClass$$AnnotationMetadata.class
  • $ConferenceServiceDefinitionClass.class
  • ConferenceService.class

Micronaut

  • 8 MB velikost
  • 7 MB heap
  • start < 1s

Spring

  • 36 MB velikost
  • 33 MB heap
  • start ~ 3-4 sekundy

Micronaut

  • 8 MB velikost
  • 7 MB heap
  • start < 1s
  • 22 ms s GraalVM

Spring

  • 36 MB velikost
  • 33 MB heap
  • start ~ 3-4 s

HTTP Server

@Controller("/hello") 
public class HelloController {
    @Get("/{world}") 
    public String index(String world) {
        return "Hello" + world; 
    }
}
@Controller("/receive")
public class MessageController {

    @Post(value = "/echo", consumes = MediaType.TEXT_PLAIN) 
    String echo(@Size(max = 1024) @Body String text) { 
        return text; 
    }

}
mn create-controller Hello

HTTP Server

@Controller("/people")
public class PersonController {

    Map<String, Person> inMemoryDatastore = new LinkedHashMap<>();

    @Post
    public Single<HttpResponse<Person>> save(@Body Single<Person> person) { 
        return person.map(p -> {
                    inMemoryDatastore.put(p.getFirstName(), p); 
                    return HttpResponse.created(p); 
                }
        );
    }
}

Integrační Testy

import io.micronaut.context.ApplicationContext
import io.micronaut.http.HttpRequest
import io.micronaut.http.client.HttpClient
import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.*

class HelloControllerSpec extends Specification {

    @Shared @AutoCleanup EmbeddedServer embeddedServer =
            ApplicationContext.run(EmbeddedServer) 

    @Shared @AutoCleanup HttpClient client = HttpClient.create(embeddedServer.URL) 

    void "test hello world response"() {
        expect:
        client.toBlocking() 
              .retrieve(HttpRequest.GET('/hello/Mars')) == "Hello Mars" 
    }
}

Integrační Testy

class HelloControllerSpec extends Specification {

    @Shared @AutoCleanup EmbeddedServer embeddedServer = Application.run(EmbeddedServer)

    @Rule Gru gru = Gru.equip(Http.steal(this))

    void setup() {
        String serverUrl = embeddedServer.getURL().toString()
        gru.prepare {
            baseUri serverUrl
        }
    }

    void 'test micronaut with Gru'() {
        expect:
            gru.test {
                get '/hello/Mars'
                expect {
                    text inline('Hello Mars!')
                }
            }
    }
}

HTTP Client

@Retryable @Client("/pets") 
public interface PetClient extends PetOperations { 

    @Override
    Single<Pet> save(String name, int age); 
}
@Validated
public interface PetOperations {
    @Post
    Single<Pet> save(@NotBlank String name, @Min(1L) int age);
}

Android + Kotlin

Funkce

@Inject @Field ConferenceService conferenceService

@CompileStatic
String conference() {
    "conference"
}
mn create-function conference --lang groovy
@FunctionClient
interface ConferenceClient {

    @Named("conference")
    Single<String> conference()
}

Funkce

class ConferenceFunctionSpec extends Specification {

    void "test conference function"() {
        given:
        EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
        ConferenceClient client = server.getApplicationContext().getBean(ConferenceClient)

        expect:
        client.conference().blockingGet() == "conference"

        cleanup:
        if(server != null) server.stop()
    }
}
cd conference
./gradlew deploy

Proč věřím v Micronaut?

  • Nic nového pod sluncem
  • Tým stojící za Grails
  • Fungující business model
  • AWS Lambda FTW

Čeho se "bojím"?

  • Spring příjde s AoT kompilací

Děkuji

Workshop!

Otázky?

14:00 v salónku

Micronaut - menší už to nebude

By musketyr

Micronaut - menší už to nebude

  • 1,813