CDI – Exemplo utilizando Weld

Hoje vou falar um pouco sobre CDI(Contexts and Dependency Injection). O CDI é uma implementação de referência (JSR-299).

O CDI é uma implementação oficial e está presente em diferentes plataformas:

  • JBoss Application Server 7
  • JBoss Application Server 6
  • GlassFish V3.x
  • Apache Tomcat 6 & 7
  • Jetty 6.1 & 7.x
  • Java SE 5.0+

Este post não tem o objetivo de dizer qual é a melhor API para fazer injeção de dependência. Quero ajudar você a tirar suas próprias conclusões.

Para o nosso exemplo utilizaremos o Weld.

Antes de iniciarmos o exemplo precisamos criar o arquivo beans.xml dentro da pasta META-INF.

 

<beans 
xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

</beans>

Primeiro criaremos bean que representará uma movimentação bancária. Essa classe possui apenas um atributo value e seus respectivos métodos de acessos (get/set).

Disparando Eventos

Vamos criar uma classe para representar um caixa eletrônico. Nessa classe sempre que houver uma operação bancária essa classe disparará um evento de movimentação. Essa movimentação pode ser um depósito ou um saque.

 
/**
 * @author wmews
 */
public class ATM {

	private final Event<Handling> handlingEvent;
	private final Logger logger;

	@Inject
	public ATM(Event<Handling> handlingEvent, Logger logger) {
		super();
		this.handlingEvent = handlingEvent;
		this.logger = logger;
	}

	@Security
	public void deposit(int value) {
		logger.info("deposit = " + value);
		handlingEvent.fire(new Handling(value));
	}

	@Security
	public void take(int value) {
		logger.info("take = " + value);
		handlingEvent.fire(new Handling(-1 * value));
	}
}

@Inject – Injetando dependências

Em cima do construtor da classe foi inserido a anotação @Inject. Essa anotação, como o nome diz, faz a injeção das dependências requiridas na construção do objeto caixa eletrônico. A injeção pode ser feita com a anotação sobre o construtor e para isso é aconselhado definir os atributos da classe como privados e final. A outra forma de fazer a injeção é anotando o próprio atributo.

 @Observers – Recebendo eventos

Criaremos uma outra classe para representar uma conta bancária. Essa classe possui um método para consumir os eventos de movimentação.

 

/**
 * @author wmews
 */
@ApplicationScoped
public class BankAccount {

	@Inject
	private Logger logger;
	private int balance = 1000;

	private void receivedMoviment(@Observes Handling handling) {
		balance += handling.getValue();
		logger.info("balance = " + balance);
	}

	public int getBalance() {
		return balance;
	}

	public void setBalance(int balance) {
		this.balance = balance;
	}
}

O método receiveHandling possui a anotação @Observers para o tipo “handling”. Nesse caso, toda vez que a classe de caixa eletrônico disparar um evento de movimentação a conta bancária será atualizada. Se você não especificar o escopo dessa classe, toda vez que houver um evento será criado uma nova conta bancária. Para isso utilizamos a anotação @ApplicationScoped. Essa anotação faz com que apenas uma instância da conta bancária seja criada durante todo o escopo da aplicação.

@Interceptors – Interceptando operações

Como podemos fazer para uma movimentação financeira seja segura e de modo que fique transparente?

Os @Interceptors permitem interceptar uma operação(método) sempre que ele for utilizado. Nesse exemplo criamos a anotação @Security que direcionará a operação para um proxy para validar a operação antes e após a movimentação.

 

/**
 * @author wmews
 *
 */
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
public @interface Security {

}
 

/**
 * @author wmews
 */
@Interceptor
@Security
public class SecurityOperation {

	@Inject
	private Logger logger;

	@AroundInvoke
	public Object operation(InvocationContext context) throws Exception {
		logger.info("before operation");
		Object obj = context.proceed();
		logger.info("after operation");
		return obj;
	}
}

Além de criar e utilizar essas simples anotações é necessário ativar o Interceptor no arquivo beans.xml como mostra o exemplo abaixo:

 

<beans 
xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

	<interceptors>
		<class>br.com.mews.interceptor.SecurityOperation</class>
	</interceptors>

</beans>

@Produces – Produzindo objetos

Já vimos como fazer para injetar instâncias de objetos em uma classe. Mas, como podemos ter uma instância customizada para um tipo de objeto?

Nesse post vimos que em algumas classes a instância de Logger está sendo injedada. Para produzir instâncias de Logger específicas a classe que injetou utilizaremos a anotação @Produces.

O método que possui esta anotação será responsável por devolver a instância de um objeto baseado no seu tipo de retorno.

 

/**
 * @author wmews
 */
public class LogProduces {

	@Produces
	Logger createLogger( InjectionPoint injectionPoint ) {
		return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
	}
}

Como podemos ver isso funcionando???

Para testarmos o que aprendemos, primeiramente temos que ter as dependências configuradas. Nesse projeto estou utilizando o maven para fazer controle das dependências do projeto. Você pode utilizar como base o pom.xml:

 

<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<artifactId>weld-examples-parent</artifactId>
		<groupId>org.jboss.weld.examples</groupId>
		<version>1.1.2.Final</version>
	</parent>

	<groupId>br.com.mews</groupId>
	<artifactId>cdi-example</artifactId>
	<packaging>jar</packaging>

	<name>CDI - Example</name>

	<dependencies>
		<dependency>
			<groupId>org.jboss.weld.se</groupId>
			<artifactId>weld-se-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<profiles>
		<profile>
			<id>run</id>
			<activation>
				<property>
					<name>run</name>
				</property>
			</activation>
			<build>
				<plugins>
					<plugin>
						<executions>
							<execution>
								<id>run</id>
								<phase>package</phase>
								<goals>
									<goal>java</goal>
								</goals>
							</execution>
						</executions>
						<groupId>org.codehaus.mojo</groupId>
						<artifactId>exec-maven-plugin</artifactId>
						<configuration>
							<mainClass>org.jboss.weld.environment.se.StartMain</mainClass>
						</configuration>
					</plugin>
				</plugins>
			</build>
		</profile>
	</profiles>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<configuration>
					<archive>
						<manifest>
							<mainClass>org.jboss.weld.environment.se.StartMain</mainClass>
						</manifest>
					</archive>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<!--
		The repositories are only added for your convenience. They should be
		added to your Maven settings.xml instead of the pom.xml
	-->
	<repositories>
		<repository>
			<id>jboss-public-repository-group</id>
			<name>JBoss Public Maven Repository Group</name>
			<url>http://repository.jboss.org/nexus/content/groups/public</url>
			<layout>default</layout>
			<releases>
				<enabled>true</enabled>
				<updatePolicy>never</updatePolicy>
			</releases>
			<snapshots>
				<enabled>false</enabled>
				<updatePolicy>never</updatePolicy>
			</snapshots>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>jboss-public-repository-group</id>
			<name>JBoss Public Maven Repository Group</name>
			<url>http://repository.jboss.org/nexus/content/groups/public</url>
			<layout>default</layout>
			<releases>
				<enabled>true</enabled>
				<updatePolicy>never</updatePolicy>
			</releases>
			<snapshots>
				<enabled>true</enabled>
				<updatePolicy>never</updatePolicy>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>

</project>

Além disso criaremos uma classe Main.java.

 

/**
 * @author wmews
 */
public class Main {

	@Inject
	private ATM atm;

	public void deposit(@Observes ContainerInitialized con) {
		this.atm.deposit(10);
	}

	public void take(@Observes ContainerInitialized con) {
		this.atm.take(110);
	}

	public static void main(String[] args) {
		WeldContainer weld = new Weld().initialize();
		ATM atm = weld.instance().select(ATM.class).get();
		atm.deposit(10);
		atm.take(110);
	}
}

Você pode executar a classe main e ver no console o resultado ou através do maven executar o comando mvn -Drun. Ambos lhe darão o resultado.

No próximo post mostrarei como fazer testes unitários utilizando weld.

Fonte: http://blog.gilliard.eti.br/
Fonte: http://www.caelum.com.br/
Fonte: http://seamframework.org/Weld

Leave a Reply

Your email address will not be published. Required fields are marked *