SlideShare a Scribd company logo
Reactive microservices
with Micronaut
Álvaro Sánchez-Mariscal
@alvaro_sanchez
About me
— Developer since 2001.
— Founded Salenda in 2007.
— Grails user since v0.4.
— Working @ OCI since 2015.
— Father since 2017!
!
@alvaro_sanchez
DISCLAIMER
!
Work in progress
Introducing
 Introducing Micronaut
The productivity of Grails with the performance
of a compile-time, non-blocking framework.
— Designed from the ground up with microservices and the
cloud in mind.
— Ultra-lightweight and Reactive (based on Netty)
— Integrated AOP and Compile-Time DI for Java and Groovy.
— HTTP Client & Server.
@alvaro_sanchez
Reactive microservices
— Any Reactive Streams implementation:
— RxJava 2.x.
— Reactor 3.x.
— Akka.
— Plain old java.util.concurrent.CompletableFuture.
@alvaro_sanchez
Micronaut is small and fast!
— JAR files: 8Mb (Java) / 12Mb (Groovy).
— Spring+Groovy: 36MB / Grails: 27Mb.
— Heap size: 7Mb (Java) / 19Mb (Groovy).
— Spring+Groovy: 33Mb / Grails: 49Mb.
— Startup time: ~1 second.
— Spring / Grails: ~3-4 seconds.
@alvaro_sanchez
Features
Inversion of Control
Dependency Injection
Inversion of Control /
Dependency Injection
— Inspired from Spring.
— Compile-time: no reflection, no runtime proxies.
— JSR-330 (javax.inject) or Spring-like annotations.
— Implemented via annotation processors (Java) and
AST transformations (Groovy) that use ASM to
generate bytecode.
@alvaro_sanchez
interface Engine {
String start()
}
@Singleton
class V8Engine implements Engine {
String start() {
"Starting V8"
}
}
@Singleton
class Vehicle {
final Engine engine
@Inject Vehicle(Engine engine) {
this.engine = engine
}
String start() {
engine.start() // "Starting V8"
}
}
@alvaro_sanchez
Implicit injection via constructor
@Singleton
class WeatherService {}
@Controller('/weather')
class WeatherController {
final WeatherService weatherService
WeatherController(WeatherService weatherService) {
this.weatherService = weatherService
}
}
@alvaro_sanchez
Injectable types
— An Optional of a bean. If the bean doesn’t exist
empty() is injected. Alternatively, use @Nullable.
— An Iterable or subtype of Iterable (eg List, Collection
etc).
— A lazy Stream of beans.
— A native array of beans of a given type (Engine[]).
— A javax.inject.Provider if a circular dependency
requires it.
@alvaro_sanchez
Bean qualifiers
@Singleton
class V6Engine implements Engine { ... }
@Singleton
class V8Engine implements Engine { ... }
//Vehicle constructor
@Inject Vehicle(@Named('v8') Engine engine) {
this.engine = engine
}
@alvaro_sanchez
Bean qualifiers
@Qualifier
@Retention(RUNTIME)
@interface V8 {
}
//Vehicle constructor
@Inject Vehicle(@V8 Engine engine) {
this.engine = engine
}
@alvaro_sanchez
Refreshable beans
@Refreshable
class WeatherService {
String forecast
@PostConstruct
void init() {
forecast = "Scattered Clouds ${new Date().format('dd/MMM/yy HH:ss.SSS')}"
}
String latestForecast() {
return forecast
}
}
@alvaro_sanchez
Refreshable beans
@Controller('/weather')
class WeatherController {
@Inject
WeatherService weatherService
...
}
— Refreshable via:
— The /refresh endpoint.
— applicationContext.publishEvent(new RefreshEvent())
@alvaro_sanchez
Refreshing upon config
changes
@Bean(preDestroy = "close")
@Refreshable('mongodb')
MongoClient mongoClient(ReactiveMongoConfiguration rmc) {
return MongoClients.create(rmc.buildSettings())
}
@alvaro_sanchez
 Bean factories
@Singleton
class CrankShaft {}
@Factory
class EngineFactory {
@Bean
@Singleton
Engine v8Engine(CrankShaft crankShaft) {
new V8Engine(crankShaft)
}
}
@alvaro_sanchez
 Conditional beans
@Singleton
@Requires(beans = DataSource)
@Requires(property = "datasource.url")
class JdbcBookService implements BookService {
DataSource dataSource
public JdbcBookService(DataSource dataSource) {
this.dataSource = dataSource
}
}
@alvaro_sanchez
 Conditional beans
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PACKAGE, ElementType.TYPE})
@Requires(beans = DataSource)
@Requires(property = "datasource.url")
@interface RequiresJdbc {
}
@RequiresJdbc
class JdbcBookService implements BookService {
...
}
@alvaro_sanchez
 Supported conditions
— @Requires(classes=javax.servlet.Servlet)
— @Requires(beans=javax.sql.DataSource)
— @Requires(env='TRAVIS')
— @Requires(configuration='foo.bar')
— @Requires(sdk=Sdk.JAVA, value="1.8")
— @Requires(property='consul.enabled', value="true",
defaultValue="false")
@alvaro_sanchez
 Bean configurations
— Grouping of multiple bean definitions within a
package:
//file: src/main/groovy/com/example/json/package-info.groovy
@Configuration
@Requires(classes = com.fasterxml.jackson.databind.ObjectMapper)
package com.example.json
— All the beans from the package can be required with
@Requires(configuration='com.example.json')
@alvaro_sanchez
Life-cycle methods and events
— javax.annotation.PostConstruct is supported.
— For events:
@Singleton
class EngineInitializer implements BeanInitializedEventListener<EngineFactory> {
@Override
EngineFactory onInitialized(BeanInitializingEvent<EngineFactory> event) {
EngineFactory engineFactory = event.bean
engineFactory.rodLength = 6.6
return event.bean
}
}
@alvaro_sanchez
Application configuration
PropertySources
— Command line arguments.
— Properties from SPRING_APPLICATION_JSON (for Spring compatibility).
— Properties from MICRONAUT_APPLICATION_JSON.
— Java System Properties.
— OS environment variables.
— Enviroment-specific properties from application-{environment}.
{extension}.
— (Either .properties, .json, .yml or .groovy formats supported)
— Application-specific properties from application.{extension}.
@alvaro_sanchez
 Injecting configuration values
@Singleton
class EngineImpl implements Engine {
@Value('${my.engine.cylinders:6}')
int cylinders
}
@alvaro_sanchez
 @EachProperty
@EachProperty("myapp.datasources")
public class DataSourceConfiguration {
final String name
final URI url
}
//src/main/resources/application.properties
myapp.datasources.one = "jdbc:mysql://localhost/one"
myapp.datasources.two = "jdbc:mysql://localhost/two"
@alvaro_sanchez
 @EachBean
@Factory
class DataSourceFactory {
@EachBean(DataSourceConfiguration)
DataSource dataSource(DataSourceConfiguration cfg) {
URI url = cfg.url
return new DataSource(url)
}
}
@alvaro_sanchez
 Type-safe @ConfigurationProperties
@ConfigurationProperties('my.engine')
class EngineConfig {
@NotBlank
String manufacturer = "Ford"
@Min(1L)
int cylinders
CrankShaft crankShaft = new CrankShaft()
@ConfigurationProperties('crank-shaft')
static class CrankShaft {
Optional<Double> rodLength = Optional.empty()
}
}
@alvaro_sanchez
 Type-safe @ConfigurationProperties
#src/main/resources/application.yml
my:
engine:
manufacturer: Subaru
cylinders: 4
crank-shaft:
rodLength: 4
@alvaro_sanchez
 Type-safe @ConfigurationProperties
— Simple injection:
@Singleton
class EngineImpl implements Engine {
final EngineConfig config
EngineImpl(EngineConfig config) {
this.config = config
}
}
@alvaro_sanchez
AOP
Micronaut's AOP
— Around Advice - decorates a method or class.
— Trace logging.
— Hystrix support.
— Cache abstraction.
— Circuit breaker pattern with retry support.
— Validation.
— Introduction Advice - introduces new behaviour to a class.
— HTTP client.
@alvaro_sanchez
Cache abstraction
@Singleton
@CacheConfig("pets")
class PetService {
@Cacheable
Pet findById(Long id) { ... }
@CachePut
void save(Pet pet) { ... }
@CacheInvalidate
void delete(Pet pet) { ... }
}
@alvaro_sanchez
HTTP Server
Hello World
//src/main/groovy/example/Application.groovy
package example
import io.micronaut.runtime.Micronaut
Micronaut.run(getClass())
@alvaro_sanchez
Hello World
//src/main/groovy/example/HelloController.groovy
@Controller("/")
class HelloController {
@Get("/hello/{name}")
String hello(String name) {
return "Hello $name!"
}
}
@alvaro_sanchez
Hello World
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/Greach')) == "Hello Greach!"
}
}
@alvaro_sanchez
JUnit with Java test
public class HelloWorldTest {
private static EmbeddedServer server;
private static HttpClient client;
@BeforeClass
public static void setupServer() {
server = ApplicationContext.run(EmbeddedServer.class);
client = server.getApplicationContext().createBean(HttpClient.class, server.getURL());
}
@AfterClass
public static void stopServer() {
if(server != null) { server.stop(); }
if(client != null) { client.stop(); }
}
@Test
public void testHelloWorkd() throws Exception {
String body = client.toBlocking().retrieve("/hello/Greach");
assertEquals(body, "Hello Greach!");
}
}
@alvaro_sanchez
Declarative routing
@Get("/hello")
String hello() {
return "Hello World"
}
@Get
String hello() {
return "Hello World"
}
@alvaro_sanchez
Programmatic routing
@Singleton
class MyRoutes extends GroovyRouteBuilder {
MyRoutes(ApplicationContext beanContext) { super(beanContext) }
@Inject
void bookResources(BookController bookController, AuthorController authorController) {
GET(bookController) {
POST("/hello{/message}", bookController.&hello)
}
GET(bookController, ID) {
GET(authorController)
}
}
}
@alvaro_sanchez
Request binding
— Body: String hello(@Body String body)
— Cookies: String hello(@CookieValue String myCookie)
— Headers: String hello(@Header String contentType)
— Parameters: String hello(@Parameter String myParam)
— Special cases:
— String hello(@Header Optional<String> contentType)
— String hello(@Parameter ZonedDateTime date)
@alvaro_sanchez
Direct request/response
manipulation
@Get("/hello")
HttpResponse<String> hello(HttpRequest<?> request) {
String name = request.getParameters()
.getFirst("name")
.orElse("Nobody");
return HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo");
}
@alvaro_sanchez
Reactive request processing
@Post(consumes = MediaType.TEXT_PLAIN)
Single<MutableHttpResponse<String>> echoFlow(@Body Flowable<String> text) {
return text.collect(StringBuffer::new, StringBuffer::append)
.map(buffer ->
HttpResponse.ok(buffer.toString())
);
}
@alvaro_sanchez
Reactive responses
— Any type that implements the
org.reactivestreams.Publisher:
Flowable<String> hello() {}
— A Java's CompletableFuture instance:
CompletableFuture<String> hello() {}
— An io.micronaut.http.HttpResponse and optional
response body:
HttpResponse<Flowable<String>> hello() {}
@alvaro_sanchez
Non-reactive responses
— Any implementation of CharSequence:
String hello()
— Any simple POJO type
Book show()
@alvaro_sanchez
Threading model
The response type determines the thread pool used to
execute the request:
— Non-blocking requests will be executed in the Netty
event loop thread pool.
— Blocking requests will be executed on the I/O thread
pool.
@alvaro_sanchez
Reactive JSON parsing with
Jackson
@Post
public Single<HttpResponse<Person>> save(@Body Single<Person> person) {
return person.map(p -> {
//do something blocking, and then:
return HttpResponse.created(p);
}
);
}
@alvaro_sanchez
Non-reactive JSON parsing
If your method does not do any blocking I/O:
@Post
public HttpResponse<Person> save(@Body Person person) {
//do something, and then:
return HttpResponse.created(person);
}
@alvaro_sanchez
HTTP Client
 Basics
//src/main/groovy/example/HelloController.groovy
@Controller("/")
class HelloController {
@Get("/hello/{name}") String hello(String name) { return "Hello $name!" }
}
//src/test/groovy/example/HelloClient.groovy
@Client('/')
interface HelloClient {
@Get("/hello/{name}") String hello(String name)
}
@alvaro_sanchez
 Testing it
class HelloControllerSpec extends Specification {
@Shared @AutoCleanup EmbeddedServer embeddedServer =
ApplicationContext.run(EmbeddedServer)
void "test hello world"() {
given:
HelloClient client = embeddedServer.applicationContext.getBean(HelloClient)
expect:
client.hello("Fred") == "Hello Fred!"
}
}
@alvaro_sanchez
 Features
— Service discovery aware: Consul and Eureka support.
— Load balancing: round robin, Netflix's Ribbon.
— Reactive: based on the return types.
— Fault tolerant: retry, fallback, circuit breaker.
@alvaro_sanchez
Fallback support
@Validated
interface PetOperations<T extends Pet> {
@Get("/") Single<List<T>> list()
}
@Client(id = "pets", path = "/v1/pets")
interface PetClient extends PetOperations<Pet> {
@Get("/") Single<List<Pet>> findAll()
}
@Fallback
class PetClientFallback implements PetOperations<Pet> {
Single<List<Pet>> list() { Single.just([] as List<Pet>) }
}
@alvaro_sanchez
Retry / circuit breaker support
@Client("/dodgy-api")
@Retryable(attempts = '5', delay = '5ms')
interface ApiClient { ... }
@Singleton
@CircuitBreaker(attempts = '5', delay = '5ms', reset = '300ms')
class MyService { ... }
@alvaro_sanchez
Retryable beans
@Singleton
class Neo4jDriverBuilder {
@Retryable(ServiceUnavailableException)
Driver buildDriver() {
//build driver
}
}
@alvaro_sanchez
Serverless
Simple functions as Groovy scripts
@Field @Inject Twitter twitterClient
@CompileStatic
UpdateResult updateStatus(Message status) {
Status s = twitterClient.updateStatus(status.text)
URL url= new URL("https://twitter.com/$s.user.screenName/status/${s.id}")
return new UpdateResult(url, s.createdAt.time)
}
@alvaro_sanchez
Function beans
import java.util.function.Function
@FunctionBean('book')
class BookFunction implements Function<Book, Book> {
@Override
Book apply(Book book) {
book.title = book.title.toUpperCase()
return book
}
}
@alvaro_sanchez
Function clients
@FunctionClient
interface TweetClient {
Single<Result> updateStatus(String text)
static class Result {
URL url
}
}
@alvaro_sanchez
Testing: directly
void "run function directly"() {
expect:
new HelloWorldFunction()
.hello(new Person(name: "Fred"))
.text == "Hello Fred!"
}
@alvaro_sanchez
Testing: REST
void "run function as REST service"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
HelloClient client = server.getApplicationContext().getBean(HelloClient)
when:
Message message = client.hello("Fred").blockingGet()
then:
message.text == "Hello Fred!"
}
@alvaro_sanchez
 Testing: AWS Lambda
void "run execute function as lambda"() {
given:
ApplicationContext applicationContext = ApplicationContext.run(
'aws.lambda.functions.hello.functionName':'hello-world',
'aws.lambda.region':'us-east-1'
)
HelloClient client = applicationContext.getBean(HelloClient)
when:
Message message = client.hello("Fred").blockingGet()
then:
message.text == "Hello Fred!"
}
@alvaro_sanchez
Micronaut
Petstore
Petstore architecture
@alvaro_sanchez
Q & A
Álvaro Sánchez-Mariscal
@alvaro_sanchez

More Related Content

PDF
Reactive microservices with Micronaut - GR8Conf EU 2018
PDF
6 things you need to know about GORM 6
PDF
Serverless functions with Micronaut
PDF
Reactive programming in Angular 2
PDF
Reactive Streams and RxJava2
PDF
Reactive Thinking in Java with RxJava2
PDF
Developing, Testing and Scaling with Apache Camel - UberConf 2015
PDF
Reactive Thinking in Java
Reactive microservices with Micronaut - GR8Conf EU 2018
6 things you need to know about GORM 6
Serverless functions with Micronaut
Reactive programming in Angular 2
Reactive Streams and RxJava2
Reactive Thinking in Java with RxJava2
Developing, Testing and Scaling with Apache Camel - UberConf 2015
Reactive Thinking in Java

What's hot (20)

PDF
Apache Camel - FUSE community day London 2010 presentation
PDF
The JavaFX Ecosystem
PPTX
Angular 2 Migration - JHipster Meetup 6
PPT
sbt 0.10 for beginners?
PDF
Serverless Java on Kubernetes
PDF
Spring Booted, But... @JCConf 16', Taiwan
PPTX
Node.js primer
PDF
Micronaut For Single Page Apps
PDF
«От экспериментов с инфраструктурой до внедрения в продакшен»​
PPTX
Angular beans
PDF
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
PDF
Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...
PDF
Play framework
PPTX
Spring boot for buidling microservices
PPTX
Spring Boot & WebSocket
PDF
Using JHipster for generating Angular/Spring Boot apps
PDF
Intro to Rack
PDF
Apache Wicket: 10 jaar en verder - Martijn Dashorst
PDF
The Many Ways to Test Your React App
PDF
Using JHipster for generating Angular/Spring Boot apps
Apache Camel - FUSE community day London 2010 presentation
The JavaFX Ecosystem
Angular 2 Migration - JHipster Meetup 6
sbt 0.10 for beginners?
Serverless Java on Kubernetes
Spring Booted, But... @JCConf 16', Taiwan
Node.js primer
Micronaut For Single Page Apps
«От экспериментов с инфраструктурой до внедрения в продакшен»​
Angular beans
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
Handling 10k requests per second with Symfony and Varnish - SymfonyCon Berlin...
Play framework
Spring boot for buidling microservices
Spring Boot & WebSocket
Using JHipster for generating Angular/Spring Boot apps
Intro to Rack
Apache Wicket: 10 jaar en verder - Martijn Dashorst
The Many Ways to Test Your React App
Using JHipster for generating Angular/Spring Boot apps
Ad

Similar to Reactive microservices with Micronaut - Greach 2018 (20)

PDF
Greach 2019 - Creating Micronaut Configurations
PDF
Microservices with Micronaut
PDF
Design Patterns para Microsserviços com MicroProfile
PDF
Micronaut Deep Dive - Devoxx Belgium 2019
PDF
Microservices with Micronaut
PDF
Microservices with Micronaut
PPTX
Micronaut: A new way to build microservices
PDF
Groovy-Powered Microservices with Micronaut
PPTX
Micronaut brainbit
PDF
Native Cloud-Native: Building Agile Microservices with the Micronaut Framework
PDF
Micronaut: Evolving Java for the Microservices and Serverless Era
PDF
Micronaut Deep Dive - Devnexus 2019
PDF
Introduction to Micronaut at Oracle CodeOne 2018
PDF
Introduction to Micronaut - JBCNConf 2019
PDF
Micronaut: Changing the Micro Future
PDF
Full lifecycle of a microservice
PDF
Microservices for java architects it-symposium-2015-09-15
PDF
Micronaut Launchpad
PDF
Grails 4 and Micronaut at Devnexus 2019
PPTX
Building a µservice with Kotlin, Micronaut & GCP
Greach 2019 - Creating Micronaut Configurations
Microservices with Micronaut
Design Patterns para Microsserviços com MicroProfile
Micronaut Deep Dive - Devoxx Belgium 2019
Microservices with Micronaut
Microservices with Micronaut
Micronaut: A new way to build microservices
Groovy-Powered Microservices with Micronaut
Micronaut brainbit
Native Cloud-Native: Building Agile Microservices with the Micronaut Framework
Micronaut: Evolving Java for the Microservices and Serverless Era
Micronaut Deep Dive - Devnexus 2019
Introduction to Micronaut at Oracle CodeOne 2018
Introduction to Micronaut - JBCNConf 2019
Micronaut: Changing the Micro Future
Full lifecycle of a microservice
Microservices for java architects it-symposium-2015-09-15
Micronaut Launchpad
Grails 4 and Micronaut at Devnexus 2019
Building a µservice with Kotlin, Micronaut & GCP
Ad

More from Alvaro Sanchez-Mariscal (20)

PDF
Asynchronous and event-driven Grails applications
PDF
Practical Spring Cloud
PDF
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
PDF
Mastering Grails 3 Plugins - G3 Summit 2016
PDF
Desarrollo de aplicaciones con Grails 3, Angular JS y Spring Security
PDF
Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...
PDF
Mastering Grails 3 Plugins - GR8Conf US 2016
PDF
Mastering Grails 3 Plugins - GR8Conf EU 2016
PDF
Creating applications with Grails, Angular JS and Spring Security - GR8Conf E...
PDF
Mastering Grails 3 Plugins - Greach 2016
PDF
Creating applications with Grails, Angular JS and Spring Security
PDF
Efficient HTTP applications on the JVM with Ratpack - Voxxed Days Berlin 2016
PDF
Efficient HTTP applications on the JVM with Ratpack - JDD 2015
PDF
Stateless authentication with OAuth 2 and JWT - JavaZone 2015
PDF
Stateless authentication for microservices - GR8Conf 2015
PDF
Ratpack 101 - GR8Conf 2015
PDF
Ratpack 101 - GeeCON 2015
PDF
Stateless authentication for microservices - Spring I/O 2015
PDF
Stateless authentication for microservices - Greach 2015
PDF
Stateless authentication for microservices applications - JavaLand 2015
Asynchronous and event-driven Grails applications
Practical Spring Cloud
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Mastering Grails 3 Plugins - G3 Summit 2016
Desarrollo de aplicaciones con Grails 3, Angular JS y Spring Security
Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...
Mastering Grails 3 Plugins - GR8Conf US 2016
Mastering Grails 3 Plugins - GR8Conf EU 2016
Creating applications with Grails, Angular JS and Spring Security - GR8Conf E...
Mastering Grails 3 Plugins - Greach 2016
Creating applications with Grails, Angular JS and Spring Security
Efficient HTTP applications on the JVM with Ratpack - Voxxed Days Berlin 2016
Efficient HTTP applications on the JVM with Ratpack - JDD 2015
Stateless authentication with OAuth 2 and JWT - JavaZone 2015
Stateless authentication for microservices - GR8Conf 2015
Ratpack 101 - GR8Conf 2015
Ratpack 101 - GeeCON 2015
Stateless authentication for microservices - Spring I/O 2015
Stateless authentication for microservices - Greach 2015
Stateless authentication for microservices applications - JavaLand 2015

Recently uploaded (20)

PDF
System and Network Administration Chapter 2
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Softaken Excel to vCard Converter Software.pdf
PPTX
L1 - Introduction to python Backend.pptx
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PPTX
history of c programming in notes for students .pptx
PPTX
ISO 45001 Occupational Health and Safety Management System
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PPTX
Transform Your Business with a Software ERP System
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Digital Strategies for Manufacturing Companies
PPT
Introduction Database Management System for Course Database
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
ai tools demonstartion for schools and inter college
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
System and Network Administration Chapter 2
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Softaken Excel to vCard Converter Software.pdf
L1 - Introduction to python Backend.pptx
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
history of c programming in notes for students .pptx
ISO 45001 Occupational Health and Safety Management System
Design an Analysis of Algorithms I-SECS-1021-03
Transform Your Business with a Software ERP System
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Wondershare Filmora 15 Crack With Activation Key [2025
Digital Strategies for Manufacturing Companies
Introduction Database Management System for Course Database
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Navsoft: AI-Powered Business Solutions & Custom Software Development
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
ai tools demonstartion for schools and inter college
Adobe Illustrator 28.6 Crack My Vision of Vector Design
CHAPTER 2 - PM Management and IT Context
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...

Reactive microservices with Micronaut - Greach 2018

  • 1. Reactive microservices with Micronaut Álvaro Sánchez-Mariscal @alvaro_sanchez
  • 2. About me — Developer since 2001. — Founded Salenda in 2007. — Grails user since v0.4. — Working @ OCI since 2015. — Father since 2017! ! @alvaro_sanchez
  • 5.  Introducing Micronaut The productivity of Grails with the performance of a compile-time, non-blocking framework. — Designed from the ground up with microservices and the cloud in mind. — Ultra-lightweight and Reactive (based on Netty) — Integrated AOP and Compile-Time DI for Java and Groovy. — HTTP Client & Server. @alvaro_sanchez
  • 6. Reactive microservices — Any Reactive Streams implementation: — RxJava 2.x. — Reactor 3.x. — Akka. — Plain old java.util.concurrent.CompletableFuture. @alvaro_sanchez
  • 7. Micronaut is small and fast! — JAR files: 8Mb (Java) / 12Mb (Groovy). — Spring+Groovy: 36MB / Grails: 27Mb. — Heap size: 7Mb (Java) / 19Mb (Groovy). — Spring+Groovy: 33Mb / Grails: 49Mb. — Startup time: ~1 second. — Spring / Grails: ~3-4 seconds. @alvaro_sanchez
  • 10. Inversion of Control / Dependency Injection — Inspired from Spring. — Compile-time: no reflection, no runtime proxies. — JSR-330 (javax.inject) or Spring-like annotations. — Implemented via annotation processors (Java) and AST transformations (Groovy) that use ASM to generate bytecode. @alvaro_sanchez
  • 11. interface Engine { String start() } @Singleton class V8Engine implements Engine { String start() { "Starting V8" } } @Singleton class Vehicle { final Engine engine @Inject Vehicle(Engine engine) { this.engine = engine } String start() { engine.start() // "Starting V8" } } @alvaro_sanchez
  • 12. Implicit injection via constructor @Singleton class WeatherService {} @Controller('/weather') class WeatherController { final WeatherService weatherService WeatherController(WeatherService weatherService) { this.weatherService = weatherService } } @alvaro_sanchez
  • 13. Injectable types — An Optional of a bean. If the bean doesn’t exist empty() is injected. Alternatively, use @Nullable. — An Iterable or subtype of Iterable (eg List, Collection etc). — A lazy Stream of beans. — A native array of beans of a given type (Engine[]). — A javax.inject.Provider if a circular dependency requires it. @alvaro_sanchez
  • 14. Bean qualifiers @Singleton class V6Engine implements Engine { ... } @Singleton class V8Engine implements Engine { ... } //Vehicle constructor @Inject Vehicle(@Named('v8') Engine engine) { this.engine = engine } @alvaro_sanchez
  • 15. Bean qualifiers @Qualifier @Retention(RUNTIME) @interface V8 { } //Vehicle constructor @Inject Vehicle(@V8 Engine engine) { this.engine = engine } @alvaro_sanchez
  • 16. Refreshable beans @Refreshable class WeatherService { String forecast @PostConstruct void init() { forecast = "Scattered Clouds ${new Date().format('dd/MMM/yy HH:ss.SSS')}" } String latestForecast() { return forecast } } @alvaro_sanchez
  • 17. Refreshable beans @Controller('/weather') class WeatherController { @Inject WeatherService weatherService ... } — Refreshable via: — The /refresh endpoint. — applicationContext.publishEvent(new RefreshEvent()) @alvaro_sanchez
  • 18. Refreshing upon config changes @Bean(preDestroy = "close") @Refreshable('mongodb') MongoClient mongoClient(ReactiveMongoConfiguration rmc) { return MongoClients.create(rmc.buildSettings()) } @alvaro_sanchez
  • 19.  Bean factories @Singleton class CrankShaft {} @Factory class EngineFactory { @Bean @Singleton Engine v8Engine(CrankShaft crankShaft) { new V8Engine(crankShaft) } } @alvaro_sanchez
  • 20.  Conditional beans @Singleton @Requires(beans = DataSource) @Requires(property = "datasource.url") class JdbcBookService implements BookService { DataSource dataSource public JdbcBookService(DataSource dataSource) { this.dataSource = dataSource } } @alvaro_sanchez
  • 21.  Conditional beans @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PACKAGE, ElementType.TYPE}) @Requires(beans = DataSource) @Requires(property = "datasource.url") @interface RequiresJdbc { } @RequiresJdbc class JdbcBookService implements BookService { ... } @alvaro_sanchez
  • 22.  Supported conditions — @Requires(classes=javax.servlet.Servlet) — @Requires(beans=javax.sql.DataSource) — @Requires(env='TRAVIS') — @Requires(configuration='foo.bar') — @Requires(sdk=Sdk.JAVA, value="1.8") — @Requires(property='consul.enabled', value="true", defaultValue="false") @alvaro_sanchez
  • 23.  Bean configurations — Grouping of multiple bean definitions within a package: //file: src/main/groovy/com/example/json/package-info.groovy @Configuration @Requires(classes = com.fasterxml.jackson.databind.ObjectMapper) package com.example.json — All the beans from the package can be required with @Requires(configuration='com.example.json') @alvaro_sanchez
  • 24. Life-cycle methods and events — javax.annotation.PostConstruct is supported. — For events: @Singleton class EngineInitializer implements BeanInitializedEventListener<EngineFactory> { @Override EngineFactory onInitialized(BeanInitializingEvent<EngineFactory> event) { EngineFactory engineFactory = event.bean engineFactory.rodLength = 6.6 return event.bean } } @alvaro_sanchez
  • 26. PropertySources — Command line arguments. — Properties from SPRING_APPLICATION_JSON (for Spring compatibility). — Properties from MICRONAUT_APPLICATION_JSON. — Java System Properties. — OS environment variables. — Enviroment-specific properties from application-{environment}. {extension}. — (Either .properties, .json, .yml or .groovy formats supported) — Application-specific properties from application.{extension}. @alvaro_sanchez
  • 27.  Injecting configuration values @Singleton class EngineImpl implements Engine { @Value('${my.engine.cylinders:6}') int cylinders } @alvaro_sanchez
  • 28.  @EachProperty @EachProperty("myapp.datasources") public class DataSourceConfiguration { final String name final URI url } //src/main/resources/application.properties myapp.datasources.one = "jdbc:mysql://localhost/one" myapp.datasources.two = "jdbc:mysql://localhost/two" @alvaro_sanchez
  • 29.  @EachBean @Factory class DataSourceFactory { @EachBean(DataSourceConfiguration) DataSource dataSource(DataSourceConfiguration cfg) { URI url = cfg.url return new DataSource(url) } } @alvaro_sanchez
  • 30.  Type-safe @ConfigurationProperties @ConfigurationProperties('my.engine') class EngineConfig { @NotBlank String manufacturer = "Ford" @Min(1L) int cylinders CrankShaft crankShaft = new CrankShaft() @ConfigurationProperties('crank-shaft') static class CrankShaft { Optional<Double> rodLength = Optional.empty() } } @alvaro_sanchez
  • 32.  Type-safe @ConfigurationProperties — Simple injection: @Singleton class EngineImpl implements Engine { final EngineConfig config EngineImpl(EngineConfig config) { this.config = config } } @alvaro_sanchez
  • 33. AOP
  • 34. Micronaut's AOP — Around Advice - decorates a method or class. — Trace logging. — Hystrix support. — Cache abstraction. — Circuit breaker pattern with retry support. — Validation. — Introduction Advice - introduces new behaviour to a class. — HTTP client. @alvaro_sanchez
  • 35. Cache abstraction @Singleton @CacheConfig("pets") class PetService { @Cacheable Pet findById(Long id) { ... } @CachePut void save(Pet pet) { ... } @CacheInvalidate void delete(Pet pet) { ... } } @alvaro_sanchez
  • 37. Hello World //src/main/groovy/example/Application.groovy package example import io.micronaut.runtime.Micronaut Micronaut.run(getClass()) @alvaro_sanchez
  • 38. Hello World //src/main/groovy/example/HelloController.groovy @Controller("/") class HelloController { @Get("/hello/{name}") String hello(String name) { return "Hello $name!" } } @alvaro_sanchez
  • 39. Hello World 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/Greach')) == "Hello Greach!" } } @alvaro_sanchez
  • 40. JUnit with Java test public class HelloWorldTest { private static EmbeddedServer server; private static HttpClient client; @BeforeClass public static void setupServer() { server = ApplicationContext.run(EmbeddedServer.class); client = server.getApplicationContext().createBean(HttpClient.class, server.getURL()); } @AfterClass public static void stopServer() { if(server != null) { server.stop(); } if(client != null) { client.stop(); } } @Test public void testHelloWorkd() throws Exception { String body = client.toBlocking().retrieve("/hello/Greach"); assertEquals(body, "Hello Greach!"); } } @alvaro_sanchez
  • 41. Declarative routing @Get("/hello") String hello() { return "Hello World" } @Get String hello() { return "Hello World" } @alvaro_sanchez
  • 42. Programmatic routing @Singleton class MyRoutes extends GroovyRouteBuilder { MyRoutes(ApplicationContext beanContext) { super(beanContext) } @Inject void bookResources(BookController bookController, AuthorController authorController) { GET(bookController) { POST("/hello{/message}", bookController.&hello) } GET(bookController, ID) { GET(authorController) } } } @alvaro_sanchez
  • 43. Request binding — Body: String hello(@Body String body) — Cookies: String hello(@CookieValue String myCookie) — Headers: String hello(@Header String contentType) — Parameters: String hello(@Parameter String myParam) — Special cases: — String hello(@Header Optional<String> contentType) — String hello(@Parameter ZonedDateTime date) @alvaro_sanchez
  • 44. Direct request/response manipulation @Get("/hello") HttpResponse<String> hello(HttpRequest<?> request) { String name = request.getParameters() .getFirst("name") .orElse("Nobody"); return HttpResponse.ok("Hello " + name + "!!") .header("X-My-Header", "Foo"); } @alvaro_sanchez
  • 45. Reactive request processing @Post(consumes = MediaType.TEXT_PLAIN) Single<MutableHttpResponse<String>> echoFlow(@Body Flowable<String> text) { return text.collect(StringBuffer::new, StringBuffer::append) .map(buffer -> HttpResponse.ok(buffer.toString()) ); } @alvaro_sanchez
  • 46. Reactive responses — Any type that implements the org.reactivestreams.Publisher: Flowable<String> hello() {} — A Java's CompletableFuture instance: CompletableFuture<String> hello() {} — An io.micronaut.http.HttpResponse and optional response body: HttpResponse<Flowable<String>> hello() {} @alvaro_sanchez
  • 47. Non-reactive responses — Any implementation of CharSequence: String hello() — Any simple POJO type Book show() @alvaro_sanchez
  • 48. Threading model The response type determines the thread pool used to execute the request: — Non-blocking requests will be executed in the Netty event loop thread pool. — Blocking requests will be executed on the I/O thread pool. @alvaro_sanchez
  • 49. Reactive JSON parsing with Jackson @Post public Single<HttpResponse<Person>> save(@Body Single<Person> person) { return person.map(p -> { //do something blocking, and then: return HttpResponse.created(p); } ); } @alvaro_sanchez
  • 50. Non-reactive JSON parsing If your method does not do any blocking I/O: @Post public HttpResponse<Person> save(@Body Person person) { //do something, and then: return HttpResponse.created(person); } @alvaro_sanchez
  • 52.  Basics //src/main/groovy/example/HelloController.groovy @Controller("/") class HelloController { @Get("/hello/{name}") String hello(String name) { return "Hello $name!" } } //src/test/groovy/example/HelloClient.groovy @Client('/') interface HelloClient { @Get("/hello/{name}") String hello(String name) } @alvaro_sanchez
  • 53.  Testing it class HelloControllerSpec extends Specification { @Shared @AutoCleanup EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer) void "test hello world"() { given: HelloClient client = embeddedServer.applicationContext.getBean(HelloClient) expect: client.hello("Fred") == "Hello Fred!" } } @alvaro_sanchez
  • 54.  Features — Service discovery aware: Consul and Eureka support. — Load balancing: round robin, Netflix's Ribbon. — Reactive: based on the return types. — Fault tolerant: retry, fallback, circuit breaker. @alvaro_sanchez
  • 55. Fallback support @Validated interface PetOperations<T extends Pet> { @Get("/") Single<List<T>> list() } @Client(id = "pets", path = "/v1/pets") interface PetClient extends PetOperations<Pet> { @Get("/") Single<List<Pet>> findAll() } @Fallback class PetClientFallback implements PetOperations<Pet> { Single<List<Pet>> list() { Single.just([] as List<Pet>) } } @alvaro_sanchez
  • 56. Retry / circuit breaker support @Client("/dodgy-api") @Retryable(attempts = '5', delay = '5ms') interface ApiClient { ... } @Singleton @CircuitBreaker(attempts = '5', delay = '5ms', reset = '300ms') class MyService { ... } @alvaro_sanchez
  • 57. Retryable beans @Singleton class Neo4jDriverBuilder { @Retryable(ServiceUnavailableException) Driver buildDriver() { //build driver } } @alvaro_sanchez
  • 59. Simple functions as Groovy scripts @Field @Inject Twitter twitterClient @CompileStatic UpdateResult updateStatus(Message status) { Status s = twitterClient.updateStatus(status.text) URL url= new URL("https://twitter.com/$s.user.screenName/status/${s.id}") return new UpdateResult(url, s.createdAt.time) } @alvaro_sanchez
  • 60. Function beans import java.util.function.Function @FunctionBean('book') class BookFunction implements Function<Book, Book> { @Override Book apply(Book book) { book.title = book.title.toUpperCase() return book } } @alvaro_sanchez
  • 61. Function clients @FunctionClient interface TweetClient { Single<Result> updateStatus(String text) static class Result { URL url } } @alvaro_sanchez
  • 62. Testing: directly void "run function directly"() { expect: new HelloWorldFunction() .hello(new Person(name: "Fred")) .text == "Hello Fred!" } @alvaro_sanchez
  • 63. Testing: REST void "run function as REST service"() { given: EmbeddedServer server = ApplicationContext.run(EmbeddedServer) HelloClient client = server.getApplicationContext().getBean(HelloClient) when: Message message = client.hello("Fred").blockingGet() then: message.text == "Hello Fred!" } @alvaro_sanchez
  • 64.  Testing: AWS Lambda void "run execute function as lambda"() { given: ApplicationContext applicationContext = ApplicationContext.run( 'aws.lambda.functions.hello.functionName':'hello-world', 'aws.lambda.region':'us-east-1' ) HelloClient client = applicationContext.getBean(HelloClient) when: Message message = client.hello("Fred").blockingGet() then: message.text == "Hello Fred!" } @alvaro_sanchez
  • 67. Q & A Álvaro Sánchez-Mariscal @alvaro_sanchez