Uso de beans gerenciáveis em Aplicações Stand-Alone

Veja neste artigo como fazer uso de beans gerenciáveis através de aplicações stand-alone com Spring Framework

É comum vermos hoje em dia o uso do Spring para realizar injeção de dependências no lado do servidor, evitando que o desenvolvedor tenha que preocupar-se com a instanciação e controle das instâncias das classes que estão sendo gerenciadas.

O problema começa a aparecer quando além dessa aplicação WEB temos uma aplicação stand-alone que precisa usar os mesmos recursos gerenciáveis do Spring, em outras palavras, imagine que temos um formulário que precisa usar recursos que o Spring está gerenciando, os beans. Nesse caso precisaremos fazer uso de uma classe chamada ClassPathXmlApplicationContext para capturar a instância do Bean. Nosso artigo terá como principal foco mostrar como realizar a captura de beans do Spring através desta classe.

Projeto com Spring

É importante entender que uma aplicação stand-alone não precisa que um container como o TomCat ou um servidor de aplicação como o glassfish esteja em execução para funcionar, por isso chama-se “stand-alone”, pelo fato de conseguir manter-se ativa por si própria.

Aqui torna-se muito claro porque trabalhar com MVC (Model-View-Controller): Se você desenvolver a sua camada Model e Controller ao ponto que estes não saibam qual será o View (Mobile, Web, Standalone …) que os usará então você terá um sistema com baixo acoplamento e alta reusabilidade. Imagine que hoje nosso sistema possui uma View toda em WEB (com páginas HTML), amanhã poderemos criar mais uma View Stand-alone (com Formulários em JSE) para aqueles usuários que desejarem usar o sistema de forma privada sem nenhuma conexão externa. Você tem exatamente a mesma lógica sendo executada para duas Views distintas: essa é uma boa prática para trabalhar-se pois qualquer mudança realizada nessas camadas de lógica refletem diretamente em todas as Views ligadas a elas.

Vamos criar um projeto simples apenas para entender o que foi explicado anteriormente, uma View WEB e uma View Stand-alone conectadas ao mesmo modelo de negócio, mas em contextos diferentes. Primeiramente vamos configurar um projeto que usará o Spring e injetar uma classe.

Criamos um projeto usando o Maven, assim poderemos usar o gerenciamento de bibliotecas através do arquivo pom.xml. Nosso projeto possui a mesma estrutura apresentada na Figura 1.

Figura 1. Estrutura do projeto

Vamos entender a estrutura de pastas do nosso projeto:

Usamos o pom.xml para configurar as bibliotecas do spring e todas as suas dependências, como mostra o código da Listagem 1.

<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> <groupId>br.com.springlab</groupId> <artifactId>springlab</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>Springlab</name> <url>http://maven.apache.org</url> <properties> <org.springframework.version>3.0.6.RELEASE </org.springframework.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> </dependencies> <build> <finalName>springlab</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> <version>2.5</version> <configuration> <targetJdk>1.6</targetJdk> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> </build> </project>
Listagem 1. pom.xml

Configurado o pom.xml temos agora as bibliotecas necessárias para fazer uso dos recursos do Spring Framework, principalmente a injeção de dependências. O arquivo applicationContext.xml possui as configurações necessárias para o Spring saber o que deverá ser gerenciado por ele, como mostra a Listagem 2.

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <!-- Seta anotaçoes para serem usadas pelo Spring --> <context:annotation-config /> <!-- Define o pacote onde o Spring vai procurar por beans anotados --> <context:component-scan base-package="br.com.springlab" /> <!-- define que as transaçoes irao ser anotadas --> <tx:annotation-driven proxy-target-class="true" /> </beans>
Listagem 2. applicationcontext.xml

Nesse arquivo definimos que o Spring deverá ler as anotações realizadas no projeto, tais como @Service, @Component e etc. Logo em seguida definimos o pacote que o spring deverá ler, no caso apenas o br.com.springlab.

Pronto, nosso projeto está configurado com Spring Framework e pronto para realizar as injeções de dependências necessárias. Criaremos dois pacotes: o br.com.springlab.logic e o br.com.springlab.standalone, onde o primeiro terá a lógica que desejamos executar e o segundo apenas fará a chamada a ele.

Vejamos a classe MyLogic, presente na Listagem 3.

package br.com.springlab.logic; import org.springframework.stereotype.Service; @Service(value = "myLogic") public class MyLogic { public void showPI(){ System.out.println("Iniciando display PI"); for(int i = 1; i <= 10; i++){ System.out.println(i * Math.PI); } System.out.println("Finalizando display PI"); } }
Listagem 3. Classe MyLogic

A nossa classe MyLogic tem a anotação @Service(value = “myLogic”), isso significa que em qualquer ponto gerenciável pelo spring (apenas dentro do escopo br.com.springlab) podemos fazer chamada ao bean “myLogic” que ele deverá retornar à instância atual da classe MyLogic. O Spring trabalha com o padrão de projeto Singleton por padrão ao gerenciar essas classes, sendo a instância retornada sempre será igual enquanto a aplicação não for reiniciada, seja por um container web (Tomcat, por exemplo) ou por uma aplicação stand-alone.

A nossa lógica é bem simples, contém um método chamado showPI() que mostra o valor de PI multiplicado pelo valor de I, que é incrementado de 1 até 10, ou seja: PI * 1, PI * 2, PI * 3 e assim por diante. Essa lógica foi colocada apenas para mostrarmos o uso do Spring Context, mas você poderia usar qualquer outra lógica ou até mesmo um simples “System.out.println(“hello world from Spring Context”);” que a ideia seria a mesma.

Podemos usar essa classe gerenciável pelo Spring através de uma aplicação stand-alone ou uma página web, como JSF por exemplo. Em nosso caso vamos demonstrar como funciona o uso através do stand-alone, como mostra a Listagem 4.

package br.com.springlab.standalone; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import br.com.springlab.logic.MyLogic; public class MainApp { /** * @param args */ public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); MyLogic myLogic = (MyLogic) context.getBean("myLogic"); myLogic.showPI(); } }
Listagem 4. Aplicação stand-alone

Stand-alone trata-se de um conceito para aplicações que podem ser executadas sem ferramentas auxiliares. O Java por si só não pode ser considerado stand-alone por precisar de uma JVM para ser executado, diferente do C, que após compilado não precisa de ferramentas auxiliares. Mas em nosso contexto podemos considerar como uma aplicação stand-alone pois trata-se da execução das dependências gerenciáveis pelo Spring sem a necessidade de um servidor de aplicação ou container web.

A classe MainApp é bem simples, mas eficaz no que precisamos realizar, que no caso é o retorno do bean gerenciável MyLogic. Vejamos em detalhes:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

Criamos um objeto do tipo ClassPathXmlApplicationContext passando como parâmetro o caminho do arquivo de configuração “applicationContext.xml”, neste caso o arquivo deve estar na pasta src/main/resources, assim como explicamos logo no início. Ao passo por essa linha o console já demonstra algo sendo realizado, parecido com a Listagem 5.

Jul 09, 2015 8:15:07 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh Informações: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@556292a4: startup date [Thu Jul 09 20:15:07 BRT 2015]; root of context hierarchy Jul 09, 2015 8:15:07 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions Informações: Loading XML bean definitions from class path resource [applicationContext.xml] Jul 09, 2015 8:15:08 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons Informações: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@646282c1: defining beans Informações: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@646282c1: defining beans Informações: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@646282c1: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org .springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework .context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation .internalCommonAnnotationProcessor,myLogic,org.springframework.aop.config .internalAutoProxyCreator,org.springframework.transaction.annotation .AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor .TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor]; root of factory hierarchy [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org .springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework .context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation .internalCommonAnnotationProcessor,myLogic,org.springframework.aop.config .internalAutoProxyCreator,org.springframework.transaction.annotation .AnnotationTransactionAttributeSource#0,org.springframework.transaction .interceptor.TransactionInterceptor#0,org.springframework.transaction.config .internalTransactionAdvisor]; root of factory hierarchy [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org[org. springframework.context.annotation.internalConfigurationAnnotationProcessor,org. springframework.context.annotation.internalAutowiredAnnotationProcessor,org. springframework.context.annotation.internalRequiredAnnotationProcessor,org. springframework.context.annotation.internalCommonAnnotationProcessor,myLogic, org.springframework.aop.config.internalAutoProxyCreator,org.springframework. transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework. transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction. config.internalTransactionAdvisor]; root of factory hierarchy.springframework. context.annotation.internalRequiredAnnotationProcessor,org.springframework. context.annotation.internalCommonAnnotationProcessor,myLogic,org.springframework. aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation. AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor. TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor]; root of factory hierarchy [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor,myLogic, org.springframework.aop.config.internalAutoProxyCreator,org.springframework. transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework. transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction. config.internalTransactionAdvisor]; root of factory hierarchy [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor,myLogic, org.springframework.aop.config.internalAutoProxyCreator,org.springframework. transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework. transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction. config.internalTransactionAdvisor]; root of factory hierarchy
Listagem 5. Início do console

Lendo de forma resumida, no console percebemos que o Spring está fazendo a leitura do arquivo XML e preparando os beans para serem utilizados.

O Spring reconhece o pacote que está sendo gerenciado e permite que você capture os beans que desejar, em nosso caso usamos o seguinte:

MyLogic myLogic = (MyLogic) context.getBean("myLogic");

O getBean() retorna a instância do “myLogic” e agora podemos fazer a chamada ao método necessário:

myLogic.showPI();

E nosso retorno será:

Iniciando display PI 3.141592653589793 6.283185307179586 9.42477796076938 12.566370614359172 15.707963267948966 18.84955592153876 21.991148575128552 25.132741228718345 28.274333882308138 31.41592653589793 Finalizando display PI

Vimos neste artigo que a reusabilidade de código é um ponto importante a ser notado quando trabalhamos com qualquer tipo de projeto, principalmente com mais de uma View (mobile, web, desktop e etc.).

Neste caso o ideal é criar uma classe responsável apenas por fazer a chama aos beans, não precisando criar uma instância de ClassPathXmlApplicationContext a cada chamada, sobrecarregando muito o sistema.

Artigos relacionados