Beruflich Dokumente
Kultur Dokumente
5)
Framework para
Desenvolvimento de Aplicações
em Java
Diego Pacheco
Set/2009
Diego Pacheco
Sumário
Sobre o Autor .................................................................................................................................. 3
6. Anotações e Web
Objetivos
• Conhecer os recursos básicos de anotações do Spring Framework;
• Saber construir testes unitários utilizando TestNG com anotações e Spring
Framework.
• Saber como integrar o Spring Framework a uma aplicação Web com JSF.
• Saber como expor um bean do Spring como um JMX.
Anotações no Java
Agora com as anotações é possivel ter estes recursos de forma nativa e com muito
mais beneficios, porque este recurso já vem com o Java e o compilador do Java - o
Javac - verifica sintática e semânticamente a validade das anotações.
• SOURCE
• CLASS
• RUNTIME
A retenção do tipo SOURCE é descartada pelo compilador, ou seja, só é valida em
tempo de design. A retenção do tipo CLASS é a padrão, o compilador marca na
classe mas a JVM não mantem essa informação acessível em tempo de runtime. Se
você deseja acessar a anotação em tempo de runtime, precisa utilizar a retenção do
tipo RUNTIME e com isso você pode acessar o elemento anotado via reflection.
Além das informação sobre o tipo de retenção das anotações, quando criamos este
tipo de recurso ainda precisamos especificar qual é o alvo da anotação, ou seja, em
que tipo de elemento ela vai estar atuando. Os elementos suportados são definidos
pela enumeração java.lang.annotation.ElementType, que segue abaixo:
• TYPE
• FIELD
• METHOD
• PARAMETER
• CONSTRUCTOR
• LOCAL_VARIABLE
• ANNOTATION_TYPE
• PACKAGE
package com.blogspot.diegopacheco.springframework25.annotations.java;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Anotação que infica que um campo de uma classe nada pode ser nulo ou vazio. <br>
* Logo você é obrigado a informar um valor ao campo que for anotado com esta anotação.
*
* @author Diego Pacheco
* @version 1.0
* @since 26/09/2009
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CampoObrigatorio {
}
Código 6.1 CampoObrigatorio.Java – Anotação do Java 5
O código acima se refere a uma anotação, repare que para criar uma anotação foi
utilizado mais 3 anotaões, duas você já conhece, são referentes a política de
retenção e ao tipo de elemento anotadado.
A anotação @Documented indica que esta anotação possui Javadoc. Repare
também que para criar a anotação foi utilizado o @interface, isto é o que indica que
é uma anotação para o compilador do Java.
@CampoObrigatorio
private Integer id;
public Pessoa() { }
@Override
public String toString() {
return "id: " + id + ",Nome: " + nome;
}
}
Código 6.2 Pessoa.Java – Pojo com anotação
Repare que este é um pojo normal com dois atributos, sendo um nome do tipo
String e um id do tipo Integer, além dos construtores vazio e full e seus métodos
getters e setters.
package com.blogspot.diegopacheco.springframework25.annotations.java;
import java.lang.reflect.Field;
try{
validate(p);
System.out.println("Objeto válido!");
}catch(Exception e){
System.out.println("Objeto inválido!");
e.printStackTrace();
}
@SuppressWarnings("unchecked")
public static void validate(Pessoa p) throws Exception {
Class<Pessoa> clazz = (Class<Pessoa>) p.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(CampoObrigatorio.class))
{
field.setAccessible(true);
if (field.get(p) == null){
throw new RuntimeException("O campo
obrigatório não foi informado. Objeto inválido! ");
}
}
}
}
Porém a utilização de xml tem desvantagens, como por exemplo, ser mais propença
a erros de digitação e de configuração, além de ser menos produtivo do que as
anotações, as anotações dão muito mais produtividade e simplicidade para o
desenvolvedor.
Apartir do Spring Framework 2.5 várias anotações ficaram disponíveis para facilitar o
trabalho e prover um leque de opções maior do que existia nas outras versões da
solução. Esta versão do Spring implementa a JSR-250 que é sobre anotações padrão
do Java como @Resource, @PostConstruct, and @PreDestroy.
package com.blogspot.diegopacheco.springframework25.annotations.spring;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;
@Component
public class AnotacoesJava {
@PostConstruct
public void init(){
System.out.println("Código de inicialização...");
}
@PreDestroy
public void shutdown(){
System.out.println("Código de shutdown...");
}
}
Código 6.4 AnotacoesJava.Java – Classe que usa anotações padrão
Como você pode reparar a classe acima está utilizado duas anotações padrão do
Java @PostConstruct, and @PreDestroy que serão executadas pelo spring depois de
contruir o objeto e antes de destruir o mesmo.
Para ativar este recurso no spring é necessário registrar um bean post processor
padrão, confira esta configuração no código abaixo.
<context:annotation-config/>
<context:component-scan base-package="com.blogspot.diegopacheco"/>
</beans>
Código 6.5 spring-annotation-beans.xml – XML de configuração
Vamos ver o código para testar a utilização de anotações com o Spring Framework
2.5, confira o código abaixo:
package com.blogspot.diegopacheco.springframework25.annotations.spring;
import org.springframework.context.support.AbstractApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
}
}
Código 6.6 TestaAnotacoesJava – Classe para testes
• @Component
• @Service
• @Repository
• @Controller
Caso ele encontre algum bean com alguma destas anotações, ele vai registrar o
bean no contexto, o nome do bean vai ser definido da seguinte forma: Supondo
que a classe se chama PessoaFisicaService o bean ter o mesmo nome só que com a
primeira letra não captalizada, ou seja: pessoaFisicaService.
A anotação @Component é a mais genérica do Spring, ela serve para indicar que é
um bean gerenciado pelo Spring, você utiliza isso em qualquer bean de propósito
geral.
Quando você utiliza @Service, @Component ou @Controller ainda não tem uma
diferença prática, mas o spring pretende utilizar isso como informações para
aspéctos em futuras implementações.
• @Resource
• @Autowired
A anotação @Resource faz a injeção baseado nos nomes dos beans e a anotação
@Autowired faz baseada em tipos. Se você não trabalha com interfaces ou tem só
uma implementação, pode usar @Autowired sem problemas, mas a sua aplicação
pode crescer e com isso podem vir vários erros de injeção.
import org.springframework.stereotype.Component;
@Component
public class Livro {
public Livro() {
isbn = "10ergregKL2";
titulo = "O código de Da vince";
}
@Override
public String toString() {
return "[livro={isbn: " + isbn + ",titulo: " + titulo + "}]";
}
}
Código 6.7 Livro.java – Pojo Livro
Este é um pojo simples, que foi anotado com a anotação @Component do spring
framework 2.5, agora vamos ao bean autor, neste bean vamos injetar o código do
livro que está acima.
package com.blogspot.diegopacheco.springframework25.annotations.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component()
public class Autor {
@Autowired
private Livro livro;
public Autor() {
id=0;
nome="Sem nome";
}
@Override
public String toString() {
return "id: " + id + ",Nome: " + nome + ", Livro: " + livro;
}
Como você pode perceber, foi utilziado a anotação @Autowired, para realizar a
injeção, neste caso também poderíamos utilizar a anotação @Resource. Vamos ao
código que sobe o contexto do Spring e por fim ao teste desta aplicação.
<context:annotation-config/>
<context:component-scan base-package="com.blogspot.diegopacheco"/>
</beans>
package com.blogspot.diegopacheco.springframework25.annotations.spring;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
Você já deve ter reparado que esta abordagem tem todas as vantagens que
descrevi no início deste capítulo, mas ainda tem mais uma desvantagem, nós não
conseguimos definir vários beans com a mesma classe e com dados diferentes,
neste sentido a abordagem de xml é mais vantajosa.
Nós poderiamos deixar alguma injeção obrigatória e caso você não faça isso o
spring irá levantar uma exception. Para isso vamos utilizar a anotação @Required,
confira o código abaixo modificado do exemplo anterior.
package com.blogspot.diegopacheco.springframework25.annotations.spring;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Component;
@Component
public class Livro {
public Livro() {
isbn = "10ergregKL2";
titulo = "O código de Da vince";
}
@Required
public void setIsbn(String isbn) {
this.isbn = isbn;
}
@Override
public String toString() {
return "[livro={isbn: " + isbn + ",titulo: " + titulo + "}]";
}
<context:annotation-config/>
<context:component-scan base-package="com.blogspot.diegopacheco"/>
<bean id="livro"
class="com.blogspot.diegopacheco.springframework25.annotations.spring.Liv
ro"
>
<property name="isbn" value="1000ISBN12" />
</bean>
</beans>
Código 6.12 spring-annotation-beans.xml xml de configuração
O Spring prove injeção para testes de forma diferenciada da injeção para a sua
aplicação utiliza este recurso. Vamos ver como utilizar alguns recursos de testes
unitários do Spring com anotações, confira o código abaixo:
package com.blogspot.diegopacheco.springframework25.testng;
package com.blogspot.diegopacheco.springframework25.testng;
import org.springframework.stereotype.Service;
@Service
public class CalculadoraAsync implements Calculadora {
@Override
public void dividir(final Double va, final Double vb,
final
ResultadoCallback callback) {
new Runnable(){
public void run() {
callback.processar(va/vb);
}
}.run();
}
}
Vamos ver como testar este código integrando o Spring ao TestNG, para isso
confira a classe abaixo de testes.
package com.blogspot.diegopacheco.springframework25.testng;
import org.springframework.stereotype.Service;
@Service
public class CalculadoraAsync implements Calculadora {
@Override
public void dividir(final Double va, final Double vb,
final
ResultadoCallback callback) {
new Runnable(){
public void run() {
callback.processar(va/vb);
}
}.run();
}
}
Agora que já temos o que testar vamos criar um teste unitário com o TestNG,
confira o código de testes abaixo:
package com.blogspot.diegopacheco.springframework25.testng;
import junit.framework.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import
org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;
@Test(groups={"curso-spring"})
@ContextConfiguration(locations={"/spring-test-beans.xml"})
public class CalculadoraTest extends AbstractTestNGSpringContextTests {
@Test
public void testInjecaoSpring(){
Assert.assertNotNull("A calculadora não foi injetada.",calc);
}
@Autowired
@Test(enabled=false)
public void setCalc(Calculadora calc) {
this.calc = calc;
}
• @Test: Indica que a classe é testável via TestNG e que a classe pertence ao
grupo de testes chamado curso-spring.
Agora vamos ver outros recursos do Spring com o TestNG, podemos utilizar
diversas anotações que nos provem diversas facilidades como:
Java Server Faces vem se tornando muito popular no desenvolvimento de aplicações Web
com Java pela quantidade componentes prontos de riqueza visual dos seus componentes.
O Spring Framework 2.5 possui integração com o Java Server Faces 2.5, vamos ver como
configurar esta integração em uma aplicação Web utilizando o padrão MVC.
Este padrão é largamente utilizado em desenvolvimento de aplicação Web com Java, JSF é
uma das implementações, mas existem outras como o Strus, Webwork, Stripes, etc.
Então vamos ver essas configurações na prática e bem como uma aplicação com todas as
camadas típicas da arquitetura MVC usando Spring Framework, JSF, Jboss RichFaces e
Annotations.
<listener>
<listener-
class>org.springframework.web.context.ContextLoaderListener</listener-
class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener</lis
tener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-
class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jsp</param-value>
</context-param>
<listener>
<listener-
class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<context-param>
<param-name>com.sun.faces.verifyObjects</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.validateXml</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>org.richfaces.SKIN</param-name>
<param-value>laguna</param-value>
</context-param>
</web-app>
Como você pode perceber, as configurações de Spring, JSF e Jboss RichFaces estão
separadas por comentários, vamos ver o significado de cada configuração uma a uma,
começando com as configurações do Spring Framework.
O parametro para Servlets chamado contextConfigLocation serve para indicar aonde estão
as configurações em xml do spring para serem utilizadas na startup do contexto. Na
sequencia o listener do spring chamado
org.springframework.web.context.ContextLoaderListener é responsável por subir o
contexto do spring nesta aplicação web.
Depois vem as configurações do JSF e do Jboss RichFaces que são padrão o único ponto
mais importante a prestar atenção aqui é o parâmetro de servlet chamado
javax.faces.CONFIG_FILES que serve para informar onde estão os arquivos de configuração
do JSF.
No final do arquivo estamos registrando o filter do Jboss Richfaces, bem como a utilização
de um Skin plugável chamado laguna. Vamos ver as configurações do JSF agora, ou seja, os
faces-config.
<faces-config 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/web-facesconfig_1_2.xsd"
version="1.2">
<navigation-rule>
<navigation-case>
<from-outcome>sucesso</from-outcome>
<to-view-id>/Pages/lista-cao-pego.jsp</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
</faces-config>
Neste arquivo estão as configurações de navegação dos beans. Vamos ver o arquivo de
configuração dos managed beans e do spring com o ElResolver.
<faces-config 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/web-facesconfig_1_2.xsd"
version="1.2">
<application>
<el-
resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-
resolver>
</application>
<managed-bean>
<managed-bean-name>carrocinhaBean</managed-bean-name>
<managed-bean-
class>com.blogspot.diegopacheco.springframework25.jsf.mb.CarrocinhaBean</
managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>carrocinhaService</property-name>
<property-
class>com.blogspot.diegopacheco.springframework25.jsf.service.CarrocinhaS
ervice</property-class>
<value>#{caveiraoService}</value>
</managed-property>
</managed-bean>
</faces-config>
package com.blogspot.diegopacheco.springframework25.jsf.pojo;
import java.io.Serializable;
public Cachorro() { }
@Override
Este é um simples pojo com métodos getters e setters com o construtor vazio e que
implementa Serializable. Vamos ao componente responsável por persistir o objeto.
package com.blogspot.diegopacheco.springframework25.jsf.dao;
import java.io.Serializable;
import org.springframework.stereotype.Repository;
import com.blogspot.diegopacheco.springframework25.jsf.pojo.Cachorro;
@Repository(value="carrocinhaDao")
public class CarrocinhaDao {
}
Código 6.22 CarrocinhaDao.java– Repository de Carrocinha
package com.blogspot.diegopacheco.springframework25.jsf.service;
import java.io.Serializable;
import com.blogspot.diegopacheco.springframework25.jsf.pojo.Cachorro;
package com.blogspot.diegopacheco.springframework25.jsf.service;
import java.io.Serializable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import
com.blogspot.diegopacheco.springframework25.jsf.dao.CarrocinhaDao;
import com.blogspot.diegopacheco.springframework25.jsf.pojo.Cachorro;
@Service(value="caveiraoService")
public class CaveiraoCarrocinhaServiceImpl implements
CarrocinhaService {
@Autowired
private CarrocinhaDao dao;
Este é o serviço implementado para carrocinha. Como você pode perceber, ele está
utilizando um dao que é injetado via anotação @Autowired. Este serviço retorna a instância do
Cachorro que foi capturado.
package com.blogspot.diegopacheco.springframework25.jsf.mb;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import com.blogspot.diegopacheco.springframework25.jsf.pojo.Cachorro;
import
com.blogspot.diegopacheco.springframework25.jsf.service.CarrocinhaService
;
@Controller(value="carrocinhaBean")
public class CarrocinhaBean {
@Resource
private CarrocinhaService carrocinhaService;
public CarrocinhaBean() {}
Esta classe é um controller, você pode reparar que ela tem as mesmas propriedades que o
pojo Cachorro tem, isto serve para separarmos objetos que trafegam na tela com os
objetos que trafegam nos serviços e nas regras de negócio.
Ao rodar esta aplicação você irá precisar das seguintes dependências em termos de jars:
A versão do Spring Framework utilizada foi a versão 2.5.6.SCE e a aplicação roda no Jetty
6.1.3, você pode obter a aplicação completa nos fontes que acompanham apostila.
package com.blogspot.diegopacheco.springframework25.jmx;
Como você pode perceber esta é um interface como outa qualquer, sem
nada de mais, apenas existe um método chamado getDate que deve
retornar uma String. Vamos ver a sua implementação.
package com.blogspot.diegopacheco.springframework25.jmx;
import java.util.Date;
Vamos registrar este bean como um bean do Spring, utilizando xml como de
costume.
<bean id="dateService"
class="com.blogspot.diegopacheco.springframework25.jmx.DateServiceImpl"
/>
</beans>
<context:annotation-config />
<context:component-scan base-package="com.blogspot" />
<bean id="dateService"
class="com.blogspot.diegopacheco.springframework25.jmx.DateServiceI
mpl" />
<bean id="exporter"
class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=DateService" value-
ref="dateService" />
</map>
</property>
</bean>
</beans>
Figura 6.30 DateServiceImpl.java – Serviço de Datas
Existem outras estratégias para exposição de beans com JMX, esta é a mais
simples, caso queira saber mais, consulte a documentação oficial do spring
framework.
Você pode acessar este MBean via um utilitário que vem junto com o JDK do
java o Jconsole, você achar o utilitário na pasta bin do seu JDK, para utilizar
o JMX é comun ter que habilitar este recurso no seu container, cada
container tem uma configuração diferente, recomendo verificar a
documentação do container que você esteja utilizando para maiores
detalhes.
Exercícios