Leaner microservices with Java 10, Spring Boot 2, and Docker arto.santala@solita.fi
Who am I? • Arto Santala • Work as software architect in Solita, producing tailored solutions to accelerate customer business • More than 20 years of experience making customers dreams come true with application of proper technologies and methodologies • Guilty of writing a lot of horrible code in the 90’s that should be burned with fire. Always aiming to improve. • Passionate about agile and automation. Trying to make every moment worthy of living.
Java 8 as platform • Java 8 is product of more than 20 years of development. Every release, more and more have been added, nothing has never been removed • Today Java 8 is a heavy platform with a lot of libraries that you will never need • Midi instruments, 1995 version of java.util.Date, Corba IIOP, applets, AWT, … • Heavier images, larger memory footprint, more attack area for vulnerabilities
Java 8 + Spring Boot Helloworld
Java 9 as platform • Modular JDK, Modular source code, Modular run-time images, Module system, Modular application packaging, Java platform module system, etc • Also: Jshell, new HTTP client (HttpRequest/HttpResponse), Process API, Pub/Sub framework, immutable set/list, Optional to Stream, etc module fi.solita.java9training.api { requires fi.solita.java9training.services; exports fi.solita.java9training.api; } Set<String> mySet = Set.of(”val1", ”val2", ”val3"); List<String> myList = List.of(”val1”,”val2”,”val3”);
Java 10 as platform • Not such a revolution, just a bit of evolution • Hard transition from Java 8 to Java 9 • Easy transition from Java 9 to 10 and 11 • GA is out there now – but do note the short support lifetime for both Java 9 and 10 var item1 = ”HELLO”; var list1 = List.of(item1,”WORLD”);
Java 10 + Spring Boot Helloworld Still fat, but getting better! Pssst, minimal Java 10 + Apache Spark web services
JSHELL REPL
JLINK jlink --module-path $JAVA_HOME/jmods --verbose --add-modules java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.man agement,java.security.jgss,java.instrument --compress 2 --no-header-files --output jdk-9- minimal-osx --no-man-pages Jlink is a new tool that allows to link modules and even JRE together as a platform specific executable. For example, you can generate a custom JRE with just the modules you need to run Spring Boot, like this: Much less attack surface, less to update, less disk use, less memory use, faster startup, etc
Java Support Roadmap http://www.oracle.com/technetwork/java/eol-135779.html
Maven source level <properties> <maven.compiler.source>10</maven.compiler.source> <maven.compiler.target>10</maven.compiler.target> </properties>
Maven compiler plugin <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <release>10</release> </configuration> <dependencies> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <!-- Use newer version of ASM --> <version>6.1.1</version> </dependency> </dependencies> </plugin>
Spring Boot 2 • Spring Boot 1.x is not going to support Java 9 or above, ever • Spring Boot 2 is out there, with support to Java 9 (and to some extent also 10) • Easiest to get started with Spring Initializr at https://start.spring.io/
Quick (stupid) test @RestController public class HelloController { @RequestMapping(method = RequestMethod.GET) public Map getGreeting() { var now = Instant.now(); return Map.of("message", String.format("It's %s", now)); } }
Typical pitfalls with Java 9/10 • package javax.xml.bind.annotation.adapters is not visible • More and more core modules are missing from core of core, so you need to either add them via command line switches, or declare module dependencies – or just as dependencies • --add-modules java.xml.bind • Illegal reflective access by org.springframework.cglib.core.ReflectUtils • Java 9/10 is starting to be more precise on accessing non-public APIs, so primarily you should find libraries that are not accessing internal APIs • Ironically, with Spring you can make this warning go away by setting –illegal-access=deny • In some cases. as short-term solution you can also play with --add- exports $module/$package=$readingmodule and --add-opens $module/$package=$readingmodule to open up types and members for deep reflection of also private internals • So mostly, just make sure dependencies and modules are declared properly, and find libraries that play nicely with Java 9/10/11 and do not leverage the deprecated internals • In future, more and more modules and packages will go out of core, so get used to this
Typical pitfalls with Java 9/10 • IllegalArgumentException at testCompilation/test phase • Maven compiler/surefire might be using older version of ASM, which can be fixed like this: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <release>10</release> </configuration> <dependencies> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>6.1.1</version> <!-- Use newer version of ASM --> </dependency> </dependencies> </plugin>
Other non-default (EE) modules • java.activation with javax.activation package • java.corba with javax.activity, javax.rmi, javax.rmi.CORBA, andorg.omg.* packages • java.transaction with javax.transaction package • java.xml.bind with all javax.xml.bind.* packages • java.xml.ws with javax.jws, javax.jws.soap, javax.xml.soap, and alljavax.xml.ws.* packages • java.xml.ws.annotation with javax.annotation package • Java 11 will remove all these, so it will not be enough to just --add-modules forever, you need to find the actual libraries and declare as real, external dependencies
XML modules will go out from core <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency>
Evaluating old code • java --list-modules • jdeps --jdk-internals -R --class-path 'libs/*' $project • --illegal-access=$value option, where $value can be: • permit: Access to all JDK-internal APIs is permitted to code on the class path. For reflective access, a single warning is issued for the first access to each package. (Default is Java 9, but will be removed in a future release.) • warn: Behaves like permit but a warning is issued for each reflective access. • debug: Behaves like warn but a stack trace is included in each warning. • deny: The option for those who believe in strong encapsulation: • All illegal access is forbidden by default. • jar –file=mylib.jar --describe-modules • To figure out automatic module name for the .jar
Typical pitfalls with Spring Boot 2 • Security module has changed a lot: Now you only get what you declare, unlike previously when there were a lot of defaults • Spring Data APIs have changed a lot: Now there’s a lot more of Optional use for return values, and more descriptive names for methods • Later version of Flyway, not checksum compatible with old version possibly • References to old versions of Spring modules, or third party modules that depend on 1.x versions
Docker • Docker is a lovely way to start experimenting with Java 9/10 without installing it on your own machine • docker run -it solita/jdk10 • You can map folders to Docker so you can access files in them, such as .jar files, libraries, etc – you can also expose ports where services run to host machines • docker run -it -p 8080:8080 -v `pwd`:/root solita/jdk10 • This is just an example, you can take a look and create your own docker images • How about two-phased Docker image, one step will build the modular JRE, second will package your .jar with it?
Two-phase dockerfile example FROM solita/jdk10 as packager # First stage: JDK 10 with modules required for Spring Boot RUN /opt/jdk-10/bin/jlink --module-path /opt/jdk-10/jmods --verbose --add-modules java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.secu rity.jgss,java.instrument --compress 2 --no-header-files --output /opt/jdk-10-minimal # Second stage, add only our custom jdk9 distro and our app FROM solita/jdk10 COPY --from=packager /opt/jdk-10-minimal /opt/jdk-10-minimal COPY target/*.jar /opt/ ENV JAVA_HOME=/opt/jdk-10-minimal ENV PATH="$PATH:$JAVA_HOME/bin" EXPOSE 8080 CMD java -jar /opt/*.jar
Exercise resources • https://github.com/crystoll/spring-boot-java10/ • https://hub.docker.com/r/solita/jdk10/ • https://hub.docker.com/r/solita/jdk11-ea/ • http://dev.solita.fi/2018/01/24/Java9-modules-Spring-Boot-2-Docker.html • http://dev.solita.fi/2018/03/02/Update-to-Java11.html
Other Resources • https://hub.docker.com/_/openjdk/ • https://hub.docker.com/r/solita/jdk10/ • https://stackoverflow.com/questions/48204141/replacements-for- deprecated-jpms-modules-with-java-ee-apis/ • https://blog.frankel.ch/migrating-to-java-9/1/ • https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-with-Java-9 • https://github.com/dsyer/spring-boot-java-9
Hackathexerciseon
Hackathexerciseon • Let’s try to build something with all this • Idea: API for registering thumbs up/thumbs down signals for presentation • Presentations have a name, and we register thumbs-up/thumbs-down entries for them • Let’s assume presentations have shorter code that can be used to refer to it. • Anyone can give as many entries as they like, not limited in this exercise • API should also let us know total number of thumbs-up/thumbs-down for a presentation, and could let us know most highly/lowly rated presentations • Extra exercise: • Simple UI for pressing thumbs-up/thumbs-down for a presentation • Another UI for showing outcomes • Websockets, real-time tracking of +/- • CI pipeline, AWS Fargate/EKS deployment, self-healing capabilities, go crazy
Hackathexerciseon • So, form small groups, experiment with either larger challenge or some substeps • Pull JDK10 docker image, or install JDK 10 locally, try jshell, jlink, syntax • Create Spring Boot 2.0 initializr project, compile and run with JDK 10 • Create some API and Services, to push it further. Include db? • Minimize the JDK 10 environment, see if it still runs. How are the resources doing? Can you measure them? Can you compare them? • Ask questions, try things, break things
Thanks! ARTO SANTALA Software Architect arto.santala@solita.fi +358505747452
Leaner microservices with Java 10

Leaner microservices with Java 10

  • 1.
    Leaner microservices with Java10, Spring Boot 2, and Docker arto.santala@solita.fi
  • 2.
    Who am I? •Arto Santala • Work as software architect in Solita, producing tailored solutions to accelerate customer business • More than 20 years of experience making customers dreams come true with application of proper technologies and methodologies • Guilty of writing a lot of horrible code in the 90’s that should be burned with fire. Always aiming to improve. • Passionate about agile and automation. Trying to make every moment worthy of living.
  • 3.
    Java 8 asplatform • Java 8 is product of more than 20 years of development. Every release, more and more have been added, nothing has never been removed • Today Java 8 is a heavy platform with a lot of libraries that you will never need • Midi instruments, 1995 version of java.util.Date, Corba IIOP, applets, AWT, … • Heavier images, larger memory footprint, more attack area for vulnerabilities
  • 4.
    Java 8 +Spring Boot Helloworld
  • 5.
    Java 9 asplatform • Modular JDK, Modular source code, Modular run-time images, Module system, Modular application packaging, Java platform module system, etc • Also: Jshell, new HTTP client (HttpRequest/HttpResponse), Process API, Pub/Sub framework, immutable set/list, Optional to Stream, etc module fi.solita.java9training.api { requires fi.solita.java9training.services; exports fi.solita.java9training.api; } Set<String> mySet = Set.of(”val1", ”val2", ”val3"); List<String> myList = List.of(”val1”,”val2”,”val3”);
  • 6.
    Java 10 asplatform • Not such a revolution, just a bit of evolution • Hard transition from Java 8 to Java 9 • Easy transition from Java 9 to 10 and 11 • GA is out there now – but do note the short support lifetime for both Java 9 and 10 var item1 = ”HELLO”; var list1 = List.of(item1,”WORLD”);
  • 7.
    Java 10 +Spring Boot Helloworld Still fat, but getting better! Pssst, minimal Java 10 + Apache Spark web services
  • 8.
  • 9.
    JLINK jlink --module-path $JAVA_HOME/jmods--verbose --add-modules java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.man agement,java.security.jgss,java.instrument --compress 2 --no-header-files --output jdk-9- minimal-osx --no-man-pages Jlink is a new tool that allows to link modules and even JRE together as a platform specific executable. For example, you can generate a custom JRE with just the modules you need to run Spring Boot, like this: Much less attack surface, less to update, less disk use, less memory use, faster startup, etc
  • 10.
  • 11.
  • 12.
  • 13.
    Spring Boot 2 •Spring Boot 1.x is not going to support Java 9 or above, ever • Spring Boot 2 is out there, with support to Java 9 (and to some extent also 10) • Easiest to get started with Spring Initializr at https://start.spring.io/
  • 14.
    Quick (stupid) test @RestController publicclass HelloController { @RequestMapping(method = RequestMethod.GET) public Map getGreeting() { var now = Instant.now(); return Map.of("message", String.format("It's %s", now)); } }
  • 15.
    Typical pitfalls withJava 9/10 • package javax.xml.bind.annotation.adapters is not visible • More and more core modules are missing from core of core, so you need to either add them via command line switches, or declare module dependencies – or just as dependencies • --add-modules java.xml.bind • Illegal reflective access by org.springframework.cglib.core.ReflectUtils • Java 9/10 is starting to be more precise on accessing non-public APIs, so primarily you should find libraries that are not accessing internal APIs • Ironically, with Spring you can make this warning go away by setting –illegal-access=deny • In some cases. as short-term solution you can also play with --add- exports $module/$package=$readingmodule and --add-opens $module/$package=$readingmodule to open up types and members for deep reflection of also private internals • So mostly, just make sure dependencies and modules are declared properly, and find libraries that play nicely with Java 9/10/11 and do not leverage the deprecated internals • In future, more and more modules and packages will go out of core, so get used to this
  • 16.
    Typical pitfalls withJava 9/10 • IllegalArgumentException at testCompilation/test phase • Maven compiler/surefire might be using older version of ASM, which can be fixed like this: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <release>10</release> </configuration> <dependencies> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>6.1.1</version> <!-- Use newer version of ASM --> </dependency> </dependencies> </plugin>
  • 17.
    Other non-default (EE)modules • java.activation with javax.activation package • java.corba with javax.activity, javax.rmi, javax.rmi.CORBA, andorg.omg.* packages • java.transaction with javax.transaction package • java.xml.bind with all javax.xml.bind.* packages • java.xml.ws with javax.jws, javax.jws.soap, javax.xml.soap, and alljavax.xml.ws.* packages • java.xml.ws.annotation with javax.annotation package • Java 11 will remove all these, so it will not be enough to just --add-modules forever, you need to find the actual libraries and declare as real, external dependencies
  • 18.
    XML modules willgo out from core <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency>
  • 19.
    Evaluating old code •java --list-modules • jdeps --jdk-internals -R --class-path 'libs/*' $project • --illegal-access=$value option, where $value can be: • permit: Access to all JDK-internal APIs is permitted to code on the class path. For reflective access, a single warning is issued for the first access to each package. (Default is Java 9, but will be removed in a future release.) • warn: Behaves like permit but a warning is issued for each reflective access. • debug: Behaves like warn but a stack trace is included in each warning. • deny: The option for those who believe in strong encapsulation: • All illegal access is forbidden by default. • jar –file=mylib.jar --describe-modules • To figure out automatic module name for the .jar
  • 20.
    Typical pitfalls withSpring Boot 2 • Security module has changed a lot: Now you only get what you declare, unlike previously when there were a lot of defaults • Spring Data APIs have changed a lot: Now there’s a lot more of Optional use for return values, and more descriptive names for methods • Later version of Flyway, not checksum compatible with old version possibly • References to old versions of Spring modules, or third party modules that depend on 1.x versions
  • 21.
    Docker • Docker isa lovely way to start experimenting with Java 9/10 without installing it on your own machine • docker run -it solita/jdk10 • You can map folders to Docker so you can access files in them, such as .jar files, libraries, etc – you can also expose ports where services run to host machines • docker run -it -p 8080:8080 -v `pwd`:/root solita/jdk10 • This is just an example, you can take a look and create your own docker images • How about two-phased Docker image, one step will build the modular JRE, second will package your .jar with it?
  • 22.
    Two-phase dockerfile example FROMsolita/jdk10 as packager # First stage: JDK 10 with modules required for Spring Boot RUN /opt/jdk-10/bin/jlink --module-path /opt/jdk-10/jmods --verbose --add-modules java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.secu rity.jgss,java.instrument --compress 2 --no-header-files --output /opt/jdk-10-minimal # Second stage, add only our custom jdk9 distro and our app FROM solita/jdk10 COPY --from=packager /opt/jdk-10-minimal /opt/jdk-10-minimal COPY target/*.jar /opt/ ENV JAVA_HOME=/opt/jdk-10-minimal ENV PATH="$PATH:$JAVA_HOME/bin" EXPOSE 8080 CMD java -jar /opt/*.jar
  • 23.
    Exercise resources • https://github.com/crystoll/spring-boot-java10/ •https://hub.docker.com/r/solita/jdk10/ • https://hub.docker.com/r/solita/jdk11-ea/ • http://dev.solita.fi/2018/01/24/Java9-modules-Spring-Boot-2-Docker.html • http://dev.solita.fi/2018/03/02/Update-to-Java11.html
  • 24.
    Other Resources • https://hub.docker.com/_/openjdk/ •https://hub.docker.com/r/solita/jdk10/ • https://stackoverflow.com/questions/48204141/replacements-for- deprecated-jpms-modules-with-java-ee-apis/ • https://blog.frankel.ch/migrating-to-java-9/1/ • https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-with-Java-9 • https://github.com/dsyer/spring-boot-java-9
  • 25.
  • 26.
    Hackathexerciseon • Let’s tryto build something with all this • Idea: API for registering thumbs up/thumbs down signals for presentation • Presentations have a name, and we register thumbs-up/thumbs-down entries for them • Let’s assume presentations have shorter code that can be used to refer to it. • Anyone can give as many entries as they like, not limited in this exercise • API should also let us know total number of thumbs-up/thumbs-down for a presentation, and could let us know most highly/lowly rated presentations • Extra exercise: • Simple UI for pressing thumbs-up/thumbs-down for a presentation • Another UI for showing outcomes • Websockets, real-time tracking of +/- • CI pipeline, AWS Fargate/EKS deployment, self-healing capabilities, go crazy
  • 27.
    Hackathexerciseon • So, formsmall groups, experiment with either larger challenge or some substeps • Pull JDK10 docker image, or install JDK 10 locally, try jshell, jlink, syntax • Create Spring Boot 2.0 initializr project, compile and run with JDK 10 • Create some API and Services, to push it further. Include db? • Minimize the JDK 10 environment, see if it still runs. How are the resources doing? Can you measure them? Can you compare them? • Ask questions, try things, break things
  • 28.

Editor's Notes

  • #12 If IntelliJ fails to recognize ’var’, you can do File-Invalidate Caches/Restart
  • #13 You may need to do the same with Surefire plugin
  • #25 https://stackoverflow.com/questions/49398894/unable-to-compile-simple-java-10-project-with-maven/49398936
  • #29 https://twitter.com/SolitaOy https://www.facebook.com/Solita https://www.linkedin.com/company/solita-oy/ https://www.youtube.com/user/SolitaOy