java -jar myruntime-hollow-swarm.jar my-app.war
Peter Palaga, Red Hat
Peter Palaga
Senior sustaining engineer for JBoss EAP at Red Hat
Occasional contributor to WildFly Swarm
Author of srcdeps https://github.com/srcdeps/srcdeps-maven
Java EE
Microservices architectures
WildFly Swarm
Uberjar, Fractions
Demo: "Swarmify" a traditional EE Application
Configuration
Advanced topics
Secure access (Keycloak), Service registration and discovery, Load Balancing & Circuit Breaking, and API documentation (Swagger).
Please raise your hand if you ever wrote or maintained
Java Servlet
EJB
JAX-RS Endpoint
Persistence with Hibernate
(application developer’s perspective)
A set of API specifications
Servlet, EJB, JAX-RS, JPA, JTA, CDI, JMS, …
Packaged together as an Application Server
Several implementations
WildFly/JBoss EAP, WebSphere, WebLogic, …
History since 1999, latest EE 7 from 2013, MicroProfile
Based on recent inovations
CI/CD
Linux containers
DevOps culture
Divide the functionality into reasonably small units, a.k.a. Microservices
Communication through REST or other language independent protocols
Isolation: Languages, Runtimes, Datastores, Release cycles, (DevOps) teams
Robust, mature
Well understood (performance, scalability)
Standards compliant
Integrations
Investments (workforce, code in production)
Java EE App Servers have to carry all APIs to get certified
Large in terms of disk space
(Some) slow to boot
(Some) require a lot of memory
Open source project sponsored by Red Hat
A decomposition on WildFly Java EE Application Server
Take only the APIs you need (Just enough AppServer)
Package into a single runnable JAR (Uberjar) together with your application
A self-contained JAR
Your application
The parts of WildFly necessary to run it
An internal Maven repository of dependencies
A piece of bootstrap code
Like Uberjar but contains no application code.
java -jar myruntime-hollow-swarm.jar my-app.war
Useful with layered Linux containers:
Layer n
: Hollow Uberjar runtime
Layer n+1
: the application
Reduces the provisioning overhead and boot time
This is how WildFly Swarm implements MicroProfile
Well-defined collections of capabilities
Expressed as Maven GAVs
Autodetected at build time or explicitly declared
Configurable, with reasonable defaults
May map to
WildFly subsystems (read: Java EE APIs)
Any external code (Jolokia, Netflix Ribbon, Swagger, …)
List of Fractions https://reference.wildfly-swarm.io/v/2017.3.3/
Let’s have a traditional Java EE application
<project>
...
<name>javaee7-simple-sample</name>
<packaging>war</packaging>
...
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
...
<plugin> <!-- Add the wildfly-swarm-plugin -->
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-plugin</artifactId>
<version>2017.3.3</version>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
mvn package # build
ls target # check what has
... javaee7-simple-sample-swarm.jar ... # been built
java -jar javaee7-simple-sample-swarm.jar # run the uberjar
Autodetected by wildfly-swarm-plugin
or declared explicitly:
<dependency> <!-- under dependencyManagement -->
<groupId>org.wildfly.swarm</groupId>
<artifactId>bom-all</artifactId>
<version>2017.3.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
...
<dependencies> <!-- Fraction GAVs -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>cdi</artifactId>
</dependency>
...
WildFly | WildFly Swarm (Uberjar) |
---|---|
148 MB wildfly-master.zip 177 MB unzipped | 36 MB plain Servlet 47 MB above + JAX-RS 86 MB above + CDI 100 MB above + JPA/Hibernate |
WildFly | WildFly Swarm |
---|---|
Copy and unzip WildFly Boot Configure (datasources, …) Deploy the app | Copy the uberjar to the server Run the uberjar |
WildFly Swarm:
Will not run with a security manager
No EAR deployments
No clustering
Session replication, domain management, distributed caches, message broker
Areas open for contributions from the community
public static void main(String[] args) throws Exception {
new Swarm().fraction(
new DatasourcesFraction()
.jdbcDriver("h2", (d) -> {
d.driverClassName("org.h2.Driver");
d.xaDatasourceClass("org.h2.jdbcx.JdbcDataSource");
d.driverModuleName("com.h2database.h2");
})
.dataSource("ExampleDS", (ds) -> {
ds.driverName("h2");
ds.connectionUrl("jdbc:h2:mem:test;"
+ "DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
ds.userName("sa"); ds.password("sa");
})
).start().deploy();
}
logger: # project-defaults.yml file
level: DEBUG
swarm:
port:
offset: 10
---
project: # To specify the "development" stage,
stage: development # run with
logger: # java -jar my-swarm.jar -S development
level: DEBUG
swarm:
port:
offset: 50
---
project:
stage: production
logger:
level: INFO
...
standalone.xml
Useful when migrating from a traditional WildFly deployment
Either
java -jar my-swarm.jar -c my-standalone.xml
Or package standalone.xml
in your uberjar by placing it to src/main/resources
Ensure that you have all subsystem fractions that you configure
-b 192.168.1.104
or -Dswarm.bind.address=192.168.1.104
to bind to a specific network interface
-Dswarm.port.offset=42
to shift ports - e.g. 8080 → 8122
-Dswarm.context.path=/my-app
- note that the default is /
... and many others
JBoss community project
Single sign-on (SSO) server and identity broker
|
|
|
|
<!-- pom.xml -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>topology-consul</artifactId>
</dependency>
/* Inside main() method */
JAXRSArchive deployment = ...
/* register */
deployment.as(TopologyArchive.class)
.advertise("my-time-service");
java -Dswarm.consul.url=http://127.0.0.1:8500 -jar *-swarm.jar
Either directly through ConsulClient.getAgentServices()
Or via Netflix Ribbon integration
A REST inter-process communication library
Client-side load-balancing to other services
Several implementations: round Robin, response time weighted, random, …
Integration with Service Registries
Services referenced by name rather than host
Built-in failure resiliency via Hystrix
<!-- pom.xml -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>ribbon</artifactId>
</dependency>
// discovery by
@ResourceGroup( name="my-time-service" ) // <- service name
public interface TimeService { // lookup done
// by Consul fraction
@TemplateName("currentTime")
@Http(
method = Http.HttpMethod.GET,
uri = "/"
)
@Hystrix(
fallbackHandler = TimeFallbackHandler.class
)
RibbonRequest<ByteBuf> currentTime();
// Ribbon can provide an implementation
// of the TimeService
TimeService INSTANCE = Ribbon.from(TimeService.class);
}
<!-- pom.xml -->
<dependency>
<groupId>org.wildfly.swarm</groupId> <!-- typically -->
<artifactId>swagger</artifactId> <!-- in combination -->
</dependency> <!-- with jaxrs -->
/* Inside main() method */
SwaggerArchive archive =
ShrinkWrap.create(SwaggerArchive.class, "swagger-app.war");
/* Tell swagger where our resources are */
archive.setResourcePackages("org.myorg.myresources");
curl http://localhost:8080/swagger.json
{ "swagger":"2.0",
"info":{"version":"1.0.0"},
"host":"localhost:8080",
"basePath":"/swagger",
"tags":[{"name":"time"}],
"schemes":["http"],
"paths": {
"/time/now": {
"get": {
"tags":["time"],
"summary":"Get the current time",
"description":"Returns the time as a string",
"operationId":"get",
"produces":["application/json"],
"parameters":[],
"responses": {
...
Just enough Application Server
Uberjar or Hollow uberjar
Fractions to require and configure capabilites
WildFly Swarm Plugins for Maven and Gradle
Documentation http://wildfly-swarm.io/
Examples https://github.com/wildfly-swarm/wildfly-swarm-examples
IRC channel #wildfly-swarm at freenode
Twitter @wildflyswarm