3 hour deep dive presentation by Micronaut creator, Graeme Rocher, at Devoxx Belgium 2019 showing how to use advanced features such as Aspect Oriented Programming (AOP), compiler plugins and so on. Associated YouTube video can be found at https://www.youtube.com/watch?v=S5yfTfPeue8
2. About Me
• Graeme Rocher
• Creator of Grails and Micronaut
• Principal Engineer at Object Computing
• 2018 Oracle Groundbreaker Award Winner
• Java Champion
3. Agenda
Part 1 - 45 Minutes
• Introduction to Micronaut
• Why Micronaut
• Micronaut Fundamentals
• Micronaut Test
• Bean Introspection
• Dependency Injection
• Configuration Management
4. Agenda
Part 2 - 45 Minutes
• Micronaut AOP
• Bean Validation
• Bean Events and Listeners
• Followed by a 10 Minute Break
5. Agenda
Part 3 - 45 Minutes
• Micronaut HTTP Server
• Micronaut HTTP Client
• Swagger / OpenAPI
6. Agenda
Part 4 - 35 Minutes
• Introducing Micronaut Data
• Micronaut Data JPA
• Micronaut Data JDBC
• Micronaut & GraalVM Native Image
7. Part 1 - 45 Minutes
• Introduction to Micronaut
• Why Micronaut
• Micronaut Fundamentals
• Micronaut Test
• Bean Introspection
• Dependency Injection
• Configuration Management
8. Java's Problems for
Frameworks
• Limited Annotation API
• Type Erasure
• Slow Reflection
• Reflective Data Caches
• Classpath Scanning
• Slow Dynamic Class Loading
9.
10.
11. The Micro Reality
• Frameworks based on reflection
and annotations become fat
• But we love the programming
model and productivity so
we live with it
• Why can't we be
more efficient?
12. Java's Problems
• Greatly Exaggerated (Java has been
dead forever)
• Java can be Fast! (see Android and
Micronaut)
• However Most Existing Tools are
based around
• Reflection
• Runtime Proxies
• Runtime Byte Code Generation
(bytebuddy/cglib)
13. Why is Reflection a Problem?
• Today the JDK is OpenJDK!
• Just take a look...
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/
share/classes/java/lang/Class.java#l2471
• All Reflective data initialized on first access and held in soft
references (yes every field, method etc.)
• Won't be GC'ed until your application is low on memory!
14. Avoid Reflection!
• Reflection usage increases memory
usage
• Using reflection relatively slow
• Problem is most modern server-side
frameworks and specifications
are built on reflection
• Some of the Jarkarta specifications
even mandate reflection
15. Just Like The
Android World
• The Android Community already
solved the problem
• Ahead of Time Compilation used
extensively
• Google Dagger 2.x for DI
• Most Android Frameworks avoid
reflection to
avoid paying the memory /
performance cost
16.
17. Micronaut
• A Microservices and Serverless
Focused framework (hence the
branding)
• Also a Complete Application
Framework for any type of
Application
• Dependency Injection, Aspect
Oriented Programming (AOP),
Configuration Management,
Bean Introspection and more..
18. With Micronaut You
Can Build
• Microservices
• Serverless Applications
• Message-Driven Applications with
Kafka/Rabbit
• CLI Applications
• Even Android Applications
• Anything with
static void main(String..args)
19. Micronaut History
• Development Started over 2 years
ago
• Open Sourced May 2018
• Creating waves ever since
• Inspired other frameworks to
improve
and new frameworks to be born
based on the same approach
20. Micronaut Current
Status
• Micronaut 1.2.5 current stable
release
• Built by the people that built Grails
• Nearly 3K Github Stars
• Used in production and delivering
real
savings in cloud spend to dozens of
organizations already
21.
22. Micronaut's Solutions
Problem Solution
Limited Annotation API Precomputed AnnotationMetadata
Type Erasure Precomputed Argument Interface
Slow Reflection Eliminate Reflection
Reflective Data Caches Zero Data Caches
Classpath Scanning No Classpath Scanning
Slow Dynamic Class Loading No Dynamic Class Loaders
25. Project Setup
• The Quick Way with SDKMan! (https://sdkman.io/):
$ sdk install micronaut
## For Maven
$ mn create-app example --build maven
## For Gradle
$ mn create-app example --build gradle
• Can setup manually. CLI is just a handy helper
26. Micronaut Minimum Setup
• A Micronaut project is just a Java project with an additional
annotation processor
annotationProcessor "io.micronaut:micronaut-inject-java:1.2.5" // Gradle
<annotationProcessorPaths> <!-- Maven -->
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-inject-java</artifactId>
<version>1.2.5</version>
</path>
...
27.
28. Micronaut Test
• Testing library with support for Spock and JUnit 5
https://github.com/micronaut-projects/micronaut-test
testCompile "io.micronaut.test:micronaut-test-junit5" // Gradle
<dependency> <!-- Maven -->
<groupId>io.micronaut.test</groupId>
<artifactId>micronaut-test-junit5</artifactId>
<scope>test</scope>
</dependency>
...
29. Micronaut Test
• Allows DI directly into your tests
• Spins up server if present
@MicronautTest
class MathServiceTest {
@Inject
MathService mathService;
@Test
void testCompute() {
final Integer result = mathService.compute(4);
Assertions.assertEquals(16,result);
}
}
33. AnnotationMetadata
AnnotationMetadata metadata = BeanIntrospection.getIntrospection(MyBean.class)
.getAnnotationMetadata();
if (metadata.hasStereotype(SomeAnnotation.class)) {
// do stuff
}
• AOT Computed / Merged Annotation Replacement for
Reflection based API
• Includes knowledge of meta-annotations
34. AnnotationMapper
• Map the value of one annotation to another at compilation
time
class KotlinNullableMapper implements NamedAnnotationMapper {
public String getName() {
return "org.jetbrains.annotations.Nullable";
}
public List<AnnotationValue<?>> map(
AnnotationValue<Annotation> annotation,
VisitorContext visitorContext) {
return Collections.singletonList(
AnnotationValue.builder("javax.annotation.Nullable").build()
);
}
}
39. Micronaut DI
@Inject MyBean myBean;
@Named("someOther") MyBean someOther;
• Supports and passes the javax.inject TCK
• Supports @PostContruct / @PreDestroy
• Completely reflection free and fast
• Constructor injection encouraged
40. ApplicationContext
try (ApplicationContext ctx = ApplicationContext.run()) {
MyBean myBean = ctx.getBean(MyBean.class);
}
• Entry point for running Micronaut applications
• Can be customized with ApplicationContext.build()
• Implements AutoCloseable for easy shutdown / running
bean destruction hooks
41. BeanDefinition
ApplicationContext ctx = ApplicationContext.run();
BeanDefinition<MyBean> definition
= ctx.getBeanDefinition(MyBean.class);
• Contains precomputed AnnotationMetadata and generic
type info
• Used by ApplicationContext to instantiate beans
42. BeanDefinition
• Bean definitions produced for any @Singleton
• Constructor injection used by default
• Use @Factory for beans you cannot annotate
• Compliant with javax.inject spec and TCK
45. @Requires
Conditional Beans Made Easy
@Requires(property="example.enabled")
@Requires(beans=DataSource.class)
@Requires(missingBeans=Example.class)
@Singleton
class DefaultExampleBean implements Example {
...
}
ApplicationContext context = ApplicationContext.run("example.enabled":"true")
Example example = context.getBean(Example)
47. Micronaut AOP
• Designed to be reflection free
• No runtime generated proxies or
byte code generation
• Fast and efficient thanks to smaller
stack traces
• Allow for all the typical framework
use cases:
@Transactional, @Cacheable,
@Validated etc.
48. @Executable
@Executable
void someMethod() {
...
}
• Replacement for java.lang.reflect.Method
• Only generate method handles where needed
return beanDefinition.getRequiredMethod("someMethod")
.invoke(someBean);
49. @ExecutableMethodProcessor
public class ScheduledMethodProcessor
implements ExecutableMethodProcessor<Scheduled> {
public void process(BeanDefinition<?> beanDefinition,
ExecutableMethod<?, ?> method) {
// do stuff with the bean
}
}
• Processes only methods annotated by the given type
argument
• In the above case setting up a scheduled job
50. Micronaut AOP
Annotation Stereotypes
• @Around - Allows decorating a method by surrounding it
with new behaviour (caching, transactions etc.)
• @Introduction - Allows introducing new behaviour to
existing classes and interfaces
• @Adapter - Allows adapting a method to a Single Abstract
Method (SAM) type.
52. @Around
@Retryable // @Retryable is annotated with @Around
void invokeMe() {
// do stuff
}
• Intercepts a method with a MethodInterceptor
• No runtime proxies (compile time proxies) or reflection
needed
• No FancyProxyFactoryBean or containers needed!
58. @Adapter
@Singleton
public class Application {
@EventListener
void init(StartupEvent event) {
// on startup do something
}
}
• @EventListener is a great example of adapter advice
61. Micronaut
Validation
• Support for javax.vallidation
annotations
• Partial implementation of spec
without the parts that require
reflection
• Reuses Bean Introspections to save
memory
63. Other Advice Types
• @Cacheable - cache operations (support for Redis, in-
memory etc.)
• @Transactional - use standard javax.transactional,
Spring's or which you want
• @Retryable - Built in retry support
• @CircuitBreaker - Circuit breaker pattern
• @Async - Makes events execute asynchronously
66. Micronaut Runtimes
Dependency Runtime
micronaut-http-server-netty Default Netty Server
micronaut-kafka Kafka Headless Server
micronaut-picocli PicoCLI command line app
micronaut-grpc GRPC Server
micronaut-graphql GraphQL Server
micronaut-ktor Kotlin KTOR Framework support
micronaut-function-aws-api-proxy AWS Lambda
67. Micronaut HTTP
Server
• Default Netty-based Reactive Server
• Support for both blocking and non-
blocking I/O
• Choose your reactive framework:
RxJava2, Reactor etc.
• Any annotation model: Micronaut,
Spring, JAX-RS (coming soon)
• Integrated Jackson with reflection-
free extensions
69. EmbeddedServer
try( EmbeddedServer embeddedServer
= ApplicationContext.run(EmbeddedServer.class) ) {
System.out.println(embeddedServer.getPort());
}
• The EmbeddedServer interface allows easily spinning up the
server
programmatically or in tests.
70. Controller Hello World
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.*;
@Controller("/hello")
public class HelloController {
@Get(produces = MediaType.TEXT_PLAIN)
public String index() {
return "Hello World";
}
}
• Use annotations in the io.micronaut.http.annotation
package
72. Micronaut HTTP
Client
• Netty-Based HTTP Client
• Low-level API and declarative
compile-time client
• Uses @Introduction advice to
simplify writing clients
• Reactive, CompletableFuture and
blocking support
• Built in Service Discovery support
73. Client Hello World
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.*;
@Client("/hello")
public interface HelloClient {
@Get(produces = MediaType.TEXT_PLAIN)
public String hello();
}
• Use annotations in the io.micronaut.http.annotation
package
74. Micronaut HTTP
Filters
• Filters can apply to server and/or
client
• Allow altering request/response
before proceeding
• Useful for adding headers,
authentication, tracing,
token propagation etc.
75. Micronaut Service
Discovery
• Support for Consul, Kubernetes and
Eureka
• Configuration Support for Consul,
Kubernetes, Vault,
Spring Cloud Config Server and
AWS ParameterStore
• Native Client Side Load Balancing
• Tracing with Zipkin or Jaeger
76. Micronaut Management
• Simply add micronaut-management
Endpoint Description
/info Basic information about the app
/health Health Check support
/loggers View and Mutate log config
/metrics Metrics with Micrometer
/env Resolved configuration
/refresh Refresh the app state
/routes View active routes
79. Micronaut OpenAPI
• Produces swagger.yml at
compilation time
• Easy to expose this static file to
Swagger UI.
• Doing the work at compilation time
== less memory consumption
• Uses Micronaut
TypeElementVisitor API
80. Part 4 - 35 Minutes
• Introducing Micronaut Data
• Micronaut Data JPA
• Micronaut Data JDBC
• Micronaut & GraalVM Native Image
81. Existing Data
Access Solutions
• Spring Data, GORM etc.
• Rely heavily on reflection and
runtime proxies
• Must compute queries at runtime
• Cost of computation grows as your
application grows
82. Micronaut Data
• Precomputes Queries at compilation
time
• Uses Micronaut's reflection-free AOP
• Zero runtime overhead database
access solution
• Compilation time checking
• Smaller stack traces
• JPA-QL and SQL currently supported
83. Hello Micronaut Data
• Each repository interface annotated with @JdbcRepository
• Can extend built in interfaces like CrudRepository
@JdbcRepository(dialect=Dialect.MYSQL)
interface PersonRepository
extends CrudRepository<Person,Long> {
Person findByName(String name);
}
84. CRUD Example
// Create
personRepository.save(new Person("Fred"));
// Read
Person person = personRepository.findByName("Fred");
// Update
person.updatePerson(person.getId(), "Bob");
// deleteById
person.deleteById(person.getId());
86. Micronaut and
GraalVM
• A New Universal Virtual Machine
from Oracle
• Features a native-image Tool
• Converts Java -> native machine
code using AOT
• Works well with Micronaut
• Startup time 20ms and Memory
Consumption 18MB!
http://www.graalvm.org
87. Micronaut and
GraalVM
• GraalVM is cool and a project to
keep an eye on
• Still in beta and experimental
• Micronaut optimizes for GraalVM,
but
also optimizes for regular Java (what
most people use today)
http://www.graalvm.org
91. Summary
• Micronaut Provides an Awesome Set of Framework
Primitives
• Sacrifices Compilation Speed to Gain so Much More
• Solves Problems with Spring, Jakarta EE and Java in General
• Opens the Door to GraalVM Native