Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Why you're missing out if you're not making Quarkus extensions

Why you're missing out if you're not making Quarkus extensions

Do I need an extension? And how do I write it?

Extensions are a great way of enabling your favourite library to fully take advantage of Quarkus’s capabilities. They can also be used to improve your team’s everyday workflow.

In this talk Georgios and Holly will talk through how extensions can be useful, before live-coding a simple extension. (What it does is a surprise!)

Holly Cummins

June 07, 2022
Tweet

More Decks by Holly Cummins

Other Decks in Programming

Transcript

  1. Holly Cummins @holly_cummins Georgios Andrianakis @geoand86 Red Hat Why you're

    missing out if you're not making Quarkus extensions
  2. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension Apache Camel …
  3. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension Apache Camel …
  4. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension JAX-RS extension Apache Camel …
  5. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension JAX-RS extension Apache Camel …
  6. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension JAX-RS extension Elasticsearch extension Apache Camel …
  7. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension JAX-RS extension Elasticsearch extension Apache Camel …
  8. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension JAX-RS extension Elasticsearch extension Hibernate extension Apache Camel …
  9. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension JAX-RS extension Elasticsearch extension Hibernate extension Apache Camel …
  10. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension JAX-RS extension Elasticsearch extension Hibernate extension Apache Camel Camel extension …
  11. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch Netty extension JAX-RS extension Elasticsearch extension Hibernate extension Apache Camel Camel extension …
  12. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch JWT extension Netty extension JAX-RS extension Elasticsearch extension Hibernate extension Apache Camel Camel extension …
  13. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch JWT extension Netty extension JAX-RS extension Elasticsearch extension Hibernate extension Apache Camel Camel extension …
  14. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch gRPC extension JWT extension Netty extension JAX-RS extension Elasticsearch extension Hibernate extension Apache Camel Camel extension …
  15. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch gRPC extension JWT extension Netty extension JAX-RS extension Elasticsearch extension Hibernate extension Apache Camel Camel extension …
  16. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch gRPC extension JWT extension Netty extension JAX-RS extension Elasticsearch extension Hibernate extension lots more extensions Apache Camel Camel extension …
  17. @holly_cummins @geoand86 #Quarkus #RedHat Quarkus core Hibernate JAX-RS Netty JWT

    gRPC Elasticsearch gRPC extension JWT extension Netty extension JAX-RS extension Elasticsearch extension Hibernate extension lots more extensions Apache Camel Camel extension … quarkiverse
  18. @ 
 @ </> traditional way vs quarkus way @

    
 @ </> build time runtime build time
  19. @ 
 @ </> traditional way vs quarkus way @

    
 @ </> build time runtime runtime build time
  20. 9 they load way too many classes they are way

    too dynamic but … for a normal framework …
  21. 9 they load way too many classes they are way

    too dynamic (which means they use way too much reflection) but … for a normal framework …
  22. 9 they load way too many classes they are way

    too dynamic (which means they use way too much reflection) they perform a lot of initialization at runtime but … for a normal framework …
  23. @ 
 @ </> Packaging 
 (maven, gradle…) build time

    runtime how does a framework start?
  24. @ 
 @ </> Load and parse config files, properties,

    yaml, xml, etc. build time runtime how does a framework start?
  25. @ 
 @ </> Classpath scanning and annotation discovery Attempt

    to load class to enable/disable features build time runtime how does a framework start?
  26. @ 
 @ </> Build its metamodel of the world.

    build time runtime how does a framework start?
  27. @ 
 @ </> Start thread pools, IO, etc. build

    time runtime how does a framework start?
  28. Do the work once, not at each start Get rid

    of all bootstrap classes Less time to start, less memory needed Less or no reflection nor dynamic proxies what if we initialize at build time?
  29. @ 
 @ </> build time Do the work once,

    not at each start Get rid of all bootstrap classes Less time to start, less memory needed Less or no reflection nor dynamic proxies what if we initialize at build time?
  30. @ 
 @ </> runtime build time Do the work

    once, not at each start Get rid of all bootstrap classes Less time to start, less memory needed Less or no reflection nor dynamic proxies what if we initialize at build time?
  31. “while we’re manipulating the bytecode to support native, why don’t

    we make coding … easier?” [warning: may not actually be Quarkus origin story]
  32. @holly_cummins @geoand86 #Quarkus #RedHat <persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance" version="3.0" xsi:schemalocation="https://jakarta.ee/xml/ns/

    persistence https://jakarta.ee/xml/ns/persistence/ persistence_3_0.xsd"> <!-- Define persistence unit --> <persistence-unit name="my-persistence-unit"> </persistence-unit> </persistence> persistence.xml hibernate extension
  33. @holly_cummins @geoand86 #Quarkus #RedHat <persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance" version="3.0" xsi:schemalocation="https://jakarta.ee/xml/ns/

    persistence https://jakarta.ee/xml/ns/persistence/ persistence_3_0.xsd"> <!-- Define persistence unit --> <persistence-unit name="my-persistence-unit"> </persistence-unit> </persistence> persistence.xml hibernate extension the hibernate extension makes this go away
  34. @holly_cummins @geoand86 #Quarkus #RedHat dynamic-but-static “wouldn’t it be nice if

    … 
 … but it’s too expensive to do it at runtime.”
  35. @holly_cummins @geoand86 #Quarkus #RedHat public class CassandraConnector { private Cluster

    cluster; private Session session; public void connect(String node, Integer port) { Builder b = Cluster.builder().addContactPoint(node); if (port != null) { b.withPort(port); } cluster = b.build(); session = cluster.connect(); } public Session getSession() { return this.session; } public void close() { session.close(); cluster.close(); } }
  36. @holly_cummins @geoand86 #Quarkus #RedHat public class CassandraConnector { private Cluster

    cluster; private Session session; public void connect(String node, Integer port) { Builder b = Cluster.builder().addContactPoint(node); if (port != null) { b.withPort(port); } cluster = b.build(); session = cluster.connect(); } public Session getSession() { return this.session; } public void close() { session.close(); cluster.close(); } } @Inject private QuarkusCqlSession session;
  37. @holly_cummins @geoand86 #Quarkus #RedHat recap: why extensions? • good behaviour

    in native mode • fast behaviour in normal mode (pre-do all the things) • good dev experience
  38. @holly_cummins @geoand86 #Quarkus #RedHat why write a new extension? •

    the community hasn’t written one yet • it’s your library • support a use case particular to your environment
  39. @holly_cummins @geoand86 #Quarkus #RedHat build items are communication mechanism between

    build steps framework automatically determines correct execution order and injects parameters
  40. @holly_cummins @geoand86 #Quarkus #RedHat initial state build items JarResultBuildStep GeneratedResourceBuildItem

    ConfigClassBuildItem intermediate state build items terminal state build items
  41. @holly_cummins @geoand86 #Quarkus #RedHat initial state build items JarResultBuildStep GeneratedResourceBuildItem

    ConfigClassBuildItem UnremovableBeanBuildItem intermediate state build items terminal state build items
  42. @holly_cummins @geoand86 #Quarkus #RedHat initial state build items JarResultBuildStep GeneratedResourceBuildItem

    ConfigClassBuildItem UnremovableBeanBuildItem BuildSystemTargetBuildItem intermediate state build items terminal state build items
  43. @holly_cummins @geoand86 #Quarkus #RedHat initial state build items JarResultBuildStep GeneratedResourceBuildItem

    ConfigClassBuildItem UnremovableBeanBuildItem BuildSystemTargetBuildItem LaunchModeBuildItem intermediate state build items terminal state build items
  44. @holly_cummins @geoand86 #Quarkus #RedHat initial state build items JarResultBuildStep GeneratedResourceBuildItem

    ConfigClassBuildItem UnremovableBeanBuildItem BuildSystemTargetBuildItem LaunchModeBuildItem most extensions do stuff here intermediate state build items terminal state build items
  45. @holly_cummins @geoand86 #Quarkus #RedHat what kind of things can build

    items do? Create a servlet Create a route Pull an external bean into the closed world Turn one annotation into another Add a log handler Read an extra application archive Flag a capability as present Interact with Kubernetes …
  46. @holly_cummins @geoand86 #Quarkus #RedHat open world closed world hard to

    build-time optimise easy to build-time optimise
  47. @holly_cummins @geoand86 #Quarkus #RedHat open world closed world hard to

    build-time optimise easy to build-time optimise runtime class surprise!
  48. @holly_cummins @geoand86 #Quarkus #RedHat open world closed world hard to

    build-time optimise easy to build-time optimise runtime class surprise!
  49. @holly_cummins @geoand86 #Quarkus #RedHat open world closed world hard to

    build-time optimise easy to build-time optimise no worries runtime class surprise!
  50. @holly_cummins @geoand86 #Quarkus #RedHat open world closed world hard to

    build-time optimise easy to build-time optimise no worries runtime class surprise!
  51. @holly_cummins @geoand86 #Quarkus #RedHat open world closed world hard to

    build-time optimise easy to build-time optimise uh oh, this is outside our closed world no worries runtime class surprise!
  52. @holly_cummins @geoand86 #Quarkus #RedHat extension concept bytecode recording easier than

    writing ASM (if recording isn’t optimised enough, use Gizmo to hand-craft bytecode)
  53. Example @Recorder public class CaffeineCacheBuildRecorder { // a proxy of

    this is invoked at build time // the “real” invocation happens at runtime with the CaffeineCacheInfo obtained at build time public Supplier<CacheManager> getCacheManagerSupplier(Set<CaffeineCacheInfo> cacheInfos) { return new Supplier<CacheManager>() { @Override public CacheManager get() { if (cacheInfos.isEmpty()) { return new CacheManagerImpl(Collections.emptyMap()); } else { Map<String, Cache> caches = new HashMap<>(cacheInfos.size() + 1, 1.0F); for (CaffeineCacheInfo cacheInfo : cacheInfos) { CaffeineCache cache = new CaffeineCache(cacheInfo); caches.put(cacheInfo.name, cache); } return new CacheManagerImpl(caches); } } }; } }
  54. @holly_cummins @geoand86 #Quarkus #RedHat extension concept GraalVM • Contribute GraalVM

    configuration ◦ Reflection registration ◦ Dynamic proxy registration ◦ Resource files ◦ Message bundles ◦ Etc. 
 • Provide substitutions ◦ Pieces of code that are used in place of regular library code when in native mode
  55. Substitutions @TargetClass(org.infinispan.client.hotrod.impl.RemoteCacheImpl.class) public final class SubstituteRemoteCacheImpl { @Delete private ObjectName

    mbeanObjectName; @Substitute private void registerMBean(ObjectName jmxParent) { } @Substitute private void unregisterMBean() { } @Delete public void init(OperationsFactory operationsFactory, Configuration configuration, ObjectName jmxParent) { } }
  56. Real world examples • Jackson extension 
 • Hibernate Validator

    extension 
 • Spring DI extension 
 
 Resources • http:/ /quarkus.io • https:/ /quarkus.io/guides/all-builditems • https:/ /quarkus.io/blog/quarkus-aws-cloudwatch_extension/ • https:/ /quarkus.io/blog/solving-problems-with-custom-extensions/