É 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.

Estrutura do projeto
Figura 1. Estrutura do projeto

Vamos entender a estrutura de pastas do nosso projeto:

  • src/main/java: Contém todo o código Java, tais como Beans, Helpers, Utils e etc.;
  • src/main/resourcers: Contém o arquivo de configuração do Spring (em nosso caso, mas pode possuir outros recursos que serão utilizados pelo projeto);
  • src/main/webapp: Local onde ficará o conteúdo web acessível pelo usuário;
  • src/main/webapp/WEB-INF: Local que não pode ser acessado pelo usuário mesmo sendo dentro do webapp, esta é uma exceção para que possam ser colocados arquivos de configuração, como é o caso do web.xml e as bibliotecas do 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.