Micro Profile JavaEE com Wildfly Swarm
Podemos criar aplicações
Java EE separadas, vários arquivos war, jar ou ear. Podemos ter um único
container. Porém pensando em micro serviços estaríamos assim gerando um único
ponto de falha.
Uma
alternativa seria cada serviço possuir seu próprio container. Com essa abordagem
podemos fazer um sub uso deste. Uma vez que um container possui vários serviços
embarcados, os quais podem não estar sendo usados por nossa aplicação.
É aí que uma ferramenta
como o WildFly Swarm pode facilitar. Ele é uma completa desmontagem
do Wildfly, em componentes reutilizáveis chamado frações. Assim podemos dizer
quais módulos da API JEE queremos utilizar. O Swarm utiliza o conceito de UberJar, para gerar o arquivo final. Ou
seja, um arquivo jar que contém o artefato
da aplicação e todos as dependências para que o servidor consiga rodar.
Logo teremos
um jar um pouco maior, porém
poderemos rodar a aplicação com um único java
-jar no console.
No Wildfly Swarm temos o conceito de fração, que nada mais é do que uma
funcionalidade/configuração do servidor de aplicação. Na maioria das vezes uma fração pode ser comparado (mapeado) a um subsystem do servidor de aplicação
(ex.: Datasource, Driver, Pool, socket-binding e etc…), temos outros casos em
que uma fração é uma funcionalidade que antes não tínhamos (nativamente) no
servidor de aplicação (Ex.: Jolokia, Spring, NetflixOSS ).
Para usar o Swarm precisamos importar um pom.xml do Wildfly Swarm no nosso projeto, e
adicionar um plugin que fará a geração do UberJar.
Nesse post
vamos construir uma simples aplicação rest usando o wildfly-swarm.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
<version.wildfly.swarm>2017.2.0</version.wildfly.swarm>
<version.h2>1.4.187</version.h2>
</properties>
Agora vamos
importar o arquivo pom.xml do Wildfly Swarm que tem o nome de BOM (Bill of
Materials). Se você quiser enumerar
explicitamente as frações de WildFly Swarm que seu aplicativo usa, em vez de
confiar na detecção automática, o projeto inclui um conjunto de listas de
materiais (lista de materiais), que você pode usar para evitar ter que rastrear
e atualizar versões de artefatos Maven em vários locais.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>bom</artifactId>
<version>${version.wildfly.swarm}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
WildFly Swarm
é descrito como "apenas o necessário app-server", o que significa que
é composto de lotes de peças. Seu aplicativo inclui apenas as peças de que
necessita.
Ao longo do
tempo, algumas dessas peças atingiram status "estável", enquanto
algumas são decididamente "instáveis" ou mesmo
"experimentais". Para ajudar a separar o estável do não-como-estável,
podem ser usadas diferentes listas técnicas do Maven.
bom-all
Inclui tudo.
Tudo o que é estável, instável, experimental, ou mesmo depreciado está incluído.
bom-deprecated
Inclui somente
as frações que estão depreciadas.
bom-experimental
Inclui apenas
as frações que são consideradas experimental. Eles podem desaparecer ou mudar
radicalmente entre os lançamentos.
bom-unstable
Inclui frações
que são melhores que as experimentais, mas ainda podem estar sujeitas a grandes
mudanças no seu comportamento, ou podem conter bugs.
bom-stable ou bom
Inclui apenas
frações estáveis e com uso recomendado.
Precisamos também adicionar a dependência referente à api do JavaEE e esta será provida pelo Wildfly Swarm.
Precisamos também adicionar a dependência referente à api do JavaEE e esta será provida pelo Wildfly Swarm.
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
Após isso precisamos adicionar as
dependências que queremos no servidor de aplicação.
Ao final teremos um pom.xml como o abaixo.
<!--Swarm Dependencies -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>ejb</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jpa</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>datasources</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${version.h2}</version>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>cdi</artifactId>
</dependency>
</dependencies>
Ao final teremos um pom.xml como o abaixo.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.talkingaboutjava</groupId>
<artifactId>uf-exemplo</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<name>uf</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
<version.wildfly.swarm>2017.2.0</version.wildfly.swarm>
<version.h2>1.4.187</version.h2>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>bom</artifactId>
<version>${version.wildfly.swarm}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--Java EE Api -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<!--Swarm Dependencies -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>ejb</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jpa</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>datasources</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${version.h2}</version>
</dependency>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>cdi</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<finalName>uf-wildfly-swarm</finalName>
<plugins>
<plugin>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-plugin</artifactId>
<version>${version.wildfly.swarm}</version>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.talkingaboutjava.swarm.Boot</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Com essa
configuração inicial podemos iniciar o desenvolvimento do nosso pequeno
sistema. Criaremos as respectivas classes abaixo.
@Entity
@Table(name = "UF")
public class Uf implements Serializable {
/**
*
*/
private static final long serialVersionUID = 232359273804681340L;
private String id;
private String nome;
private Long version;
/**
* Construtor padrão
*/
public Uf() {
this(null, null);
}
/**
* Construtor
*
* @param id
* {@link String}
* @param nome
* {@link String}
*/
public Uf(String id, String nome) {
setId(id);
setNome(nome);
}
@Id
@Column(name = "UF", columnDefinition = "char(2)")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Column(name = "NOME")
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
@Version
@Column(name = "VERSION")
public Long getVersion() {
return version;
}
public void setVersion(final Long version) {
this.version = version;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Uf other = (Uf) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
public class UfDAO {
@PersistenceContext
private EntityManager entityManager;
public List<Uf> buscaTodos() {
return entityManager.createQuery("select e from Uf e order by e.id desc", Uf.class).getResultList();
}
public void create(String sigla, String nome) {
entityManager.persist(new Uf(sigla, nome));
}
}
@Stateless
public class UfService {
@Inject
private UfDAO ufDAO;
public List<Uf> buscaTodos() {
return ufDAO.buscaTodos();
}
}
@Path("uf/")
public class UfRest {
@Inject
private UfService ufService;
@GET
@Path("buscaTodos")
@Produces("application/json")
public List<Uf> buscaTodos() {
return ufService.buscaTodos();
}
}
Iremos criar também uma classe
para configurar o JAX-RS para
receber as requisições no contexto a partir da raiz.
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class JaxRsConfiguration extends Application {
}
Com isso teremos nosso recurso disponível
na url /uf/buscaTodos.
Agora para conseguir rodar nossa
aplicação iremos iniciar a construção da nossa classe de Boot. Nessa classe iniciaremos o Swarm, bem como as frações que
serão necessárias para nossa aplicação.
A
primeira coisa que precisamos fazer é registrar nosso dataSource.
private static DatasourcesFraction datasourceWithH2() {
return 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");
});
}
Como estamos
sobrescrevendo o comportamento default do Wildfly Swarm precisamos ensinar ele
como ele deve fazer o deploy da nossa aplicação (ou seja, dentro do nosso .war
quais classes devem estar disponíveis, quais arquivos e etc…).
Para fazer
isso iremos usar uma biblioteca chamada ShrinkWrap da própria JBoss que serve
para criar um pacote programaticamente, ela é muito utilizada quando estamos
usando o Arquillian para testes de aceitação/integração.
Com ele
podemos criar JARArchive (.jar) e WARArchive (.war). Além desses temos outros
tipos mais especificos por exemplo RibbonArchive um archive especifico que pode
ser registrar em aplicações baseadas em Ribbon, Secured, que já injeta o
arquivo keycloak.json e já configura a parte de segurança.
Temos também
um outro tipo especifico que é JAXRSArchive que é um archive que já configura o
jax-rs e faz o binding para classe de configuração
Application/@ApplicationPath. Vamos utilizar esse archive.
Além disso
precisamos dizer que ao fazer o deploy da aplicação seja levado os arquivos
persistence.xml e beans.xml necessários para o funcionamento da JPA e CDI.
O arquivo
beans.xml deve estar dentro do diretório WEB-INF a partir do classpath e o
arquivo persistence.xml, deve estar em META-INF a partir do classpath também. E
precisaremos configurar isso também.
public static void main(String[] args) throws Exception {
Swarm swarm = new Swarm(args);
swarm.fraction(datasourceWithH2());
swarm.start();
JAXRSArchive deployment = ShrinkWrap.create(JAXRSArchive.class);
ClassLoader classLoader = Boot.class.getClassLoader();
deployment.addModule("com.h2database.h2");
deployment.addAsWebInfResource(classLoader.getResource("beans.xml"), "beans.xml");
deployment.addAsWebInfResource(classLoader.getResource("persistence.xml"), "classes/META-INF/persistence.xml");
deployment.addAsWebInfResource(classLoader.getResource("load.sql"), "classes/META-INF/load.sql");
deployment.addPackages(true, "com.talkingaboutjava");
deployment.addAllDependencies();
swarm.deploy(deployment);
}
Para que seja gerado o UberJar
devemos executar o goal package do maven (Ex.: mvn package). Ao termino dessa
execução no diretório target teremos um arquivo uf-exemplo.war e um uf-exemplo-swarm.jar
(entre outros arquivos).
O arquivo uf-exemplo-swarm.jar é
o nosso UberJar.
Para executarmos podemos faze-lo
pelo plugin do maven através de mvn wildfly-swarm:run ou executando o comando
java -jar uf-exemplo-swarm.jar.
O código fonte completo pode ser
baixado aqui.
Referencias

Comentários
Postar um comentário