O Spring.NET é um port para a linguagem .NET do famoso Projeto do Framework de integração Spring, da empresa SpringSource, atualmente uma empresa do grupo VMWare, para a linguagem Java. Tal framework já é bastante consolidado no meio Java até por, na época de sua criação, implementar tecnologias que a linguagem não tinha como padrão em sua JDK. Tecnologias estas que atualmente já fazem parte de projetos da comunidade, principalmente a CDI - Component Dependency Injection, que hoje é uma JSR na comunidade Java, sendo largamente implementada agora na versão 6 de seu JDK. O Spring Framework também deu início ao Projeto para o Enterprise JavaBeans 3.0, que utiliza muitos padrões de projeto implementados no Spring Framework e o principal deles é justamente a Injeção de Dependências, sendo esta a base de sua integração. Porém, a mesma tecnologia sendo portada para .NET ainda não teve o mesmo sucesso e nem mesmo a mesma quantidade de adeptos.
Muito disso se deve a existência de outros frameworks e contêineres para injeção de dependências tais como: Ninject, Castle Windsor dentre outros já bastante conceituados no mundo .NET. O Spring.NET pode facilmente ocupar este espaço por ser um framework de "curta curva de aprendizado", o que implica que o mesmo é bem mais fácil de se aprender e de se executar e também, a injeção de dependências. A Injeção de Dependências é apenas um de seus vários módulos e é a sua base principal. Diante disso o Spring.NET tira toda a sua vantagem diante dos outros frameworks de Injeção de dependências porque o Spring.NET não faz só este trabalho, faz mais do que isso: integra desde Camada de Acesso a Dados à Camada de Apresentação, bem como Queue Messaging, WebServices, Integração com WCF e por aí vai. Utilizando o Spring.NET como integrador de suas aplicações, ele permite e garante a estabilidade, permitindo ao desenvolvedor que não se preocupe com a sua infraestrutura: coleta de lixo, instanciação de objetos, performance e escalabilidade. Qual seria a vantagem de se usar o mesmo framework para Integrar todas as camadas? É provável que todo desenvolvedor ou arquiteto procure algo deste porte para sua aplicações, o que será decisivo para o uso ou não do Spring.NET será apenas a arquitetura e principalmente o custo e o tempo do Projeto. Entendendo bem como funciona a Injeção de Dependências, o desenvolvedor consegue dominar o Spring.NET por completo. No site da DevMedia, bem como na Revista .NET Magazine existem materiais disponíveis de sobra sobre tal assunto.
Os Módulos do Spring.NET
O Spring.NET detém 18 módulos de Integração que participam de todo o ciclo de vida de um projeto: de sua análise até os testes finais para entrega do software. Vamos listá-los:
Arquitetura de Base
Esta arquitetura é a que sustenta o Spring.NET e sobre ela que as integrações são executadas.
- Core - Núcleo principal que é utilizado como Container para Injeção de Dependências e as funcionalidades principais, que são as interfaces de uso para esta infraestrutura de Injeção.
- AOP - Aspect Oriented Programming - Programação Orientada a Aspectos contendo Suporte a Modelo AOP, Infraestrutura utilizando o Padrão de Projetos Proxy e a Biblioteca Aspect Library. O Spring.NET é um dos poucos frameworks que pode ser utilizado como container AOP também, esta tecnologia na linguagem Java já é bastante consolidada e utilizada, por isso ela também foi trazida para o Spring.NET, para que suas facilidades em Projetos também sejam exploradas pelas Equipes que utilizam o .NET.
Arquiteturas implementadas pelo Spring.NET para integração.
São as arquiteturas de integração propriamente ditas que o Spring disponibiliza tendo esta integração sempre facilitada pela Injeção de Dependências. Temos os seguintes módulos:
- Camada de Dados (Gerenciamento de Transação): NHibernate;
- Mensageria (Messaging) (Utilizando sempre através do Microsoft MSMQ): Apache NMS, Tibco EMS;
- Serviços (Abstração de Serviços Portáveis, ou seja, WebServices, SOA e afins): Enterprise Services, Web Services e Serviços WCF.
- Camada de Apresentação: MVC
- Teste Unitário: NUnit e MSTest
- Scheduling ou Agendamento de Tarefas: Quartz.NET
Neste artigo vamos implementar a Arquitetura básica e o Módulo de Core.
Figura 2: Módulos do Spring.NET
A Figura 1 nos dá uma impressão do tamanho deste framework e suas implementações internas.
Injeção de Dependências com o Spring.NET
O Spring.NET e seu assembly Spring.Core implementam a Injeção de Dependências utilizando os dois tipos existentes: via Setter e via Construtor. Tomemos como exemplo uma Classe que fará a persistência de um Cliente e uma classe que será responsável por abrir a conexão com a Base de Dados. Para este exemplo usamos as classes respectivamente: ClienteDAL e Conexao. Estas duas classes nos farão compreender melhor os dois tipos de Injeção de Dependências existentes e como estes são utilizados pelo Spring.NET.
Injeção de Dependências via Construtor
Neste tipo de Injeção, A classe injetada estará encapsulada dentro de um parâmetro que será passado ao construtor, lembrando que este parâmetro deve ser tipado com a classe a ser injetada, como mostra as Listagens 1 e 2:
Listagem 1: Classe Conexao
public class Conexao{
#region Construtor
//Digitando ctor e pressionando a tecla TAB duas vezes
//O Visual Studio cria um construtor padrão
public Conexao()
{
//Algoritmo para acesso ao Banco de Dados
}
#endregion
}
Esta nossa classe Conexão fará o acesso ao Banco de Dados e será necessária em nossa classe de persistência. Esta será injetada no construtor da Classe ClienteDAL via parâmetro tipado como Conexao, como mostrado na Listagem 2.
Listagem 2: Injeção da Classe Conexão no construtor de ClienteDAL
#region Propriedades
/// <summary>
/// Propriedade que será utilizada para Injeção via Construtor
/// </summary>
public Conexao conector { get; set; }
#endregion
#region Construtores
public ClienteDAL()
{
}
/// <summary>
/// Construtor para Injeção de Dependências
/// via Construtor
/// </summary>
/// <param name="conexao"></param>
public ClienteDAL(Conexao conexao)
{
this.conector = conexao;
}
#endregion
Neste ponto, observando o construtor da classe ContatoDAL, podemos notar que o parâmetro chamado conexao está tipado com a nossa classe Conexao, logo, já temos a nossa injeção de dependências pronta para uso. O Spring.NET utiliza do padrão singleton juntamente com o Service Locator, ou seja, abre apenas uma instância desta classe diretamente. Caso a mesma não esteja instanciada, ela o é automaticamente, sempre que o construtor é ativado, o que torna o uso bastante racional. Pronto, agora você já pode usar seus métodos de persistência preocupando-se apenas com as operações de CRUD.
Injeção de Dependências via Setter
Nesta modalidade de Injeção de Dependências, utilizamos um "setter" para que nele possamos Injetar a Classe que proverá todo o serviço necessário, como podemos ver na Listagem 3.
Neste modo, podemos utilizar uma interface para enriquecer a nossa codificação, posto que no momento da implementação da Injeção, podemos fazer com que a classe injetada possa utilizar a interface, facilitando a abstração em um ambiente de “Mundo Real”. Neste momento, vamos utilizar esta injeção via setter em uma classe de regra de negócio que irá utilizar a interface IClienteDAL para prover a injeção de dependências para ClienteDAL
Listagem 3: Interface IClienteDAL
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IntroSpringNet.Modelo;
namespace IntroSpringNet.Persistencia
{
public interface IClienteDAL
{
void Salvar(Cliente cliente);
}
}
Agora que criamos a nossa interface, vamos criar um trecho de código para exemplificar esta injeção.
Listagem 4: Exemplificando a injeção
#region Propriedades
public IClienteDAL DAL { get; set; }
#endregion
#region Métodos
public Boolean CadastrarCliente(Cliente cliente)
{
DAL.Salvar(cliente);
return true;
}
#endregion
Podemos ver na que a propriedade DAL recebe a interface IClienteDAL que receberá a injeção de ClienteDAL. A classe CadastrarCliente utiliza DAL e não há a necessidade de instanciar o objeto, posto que o Spring já está controlando o objeto em seu contêiner via setter.
Como o Spring gerencia os Objetos para a DI.
O Spring.NET tem uma forma peculiar de gerenciar seus objetos, todos estes objetos são registrados em um arquivo .xml, ele pode ser os descritores do próprio .NET, ou seja, os arquivos .config – App.Config se standalone ou Web.Config se Web. Pode-se utilizar estes arquivos ou nestes arquivos fazer um apontamento para outro XML, posto que o Spring.NET tem um cabeçalho bem peculiar. Na Listagem 5 temos um exemplo de arquivo .xml com header e configuração de gerência de objetos registrados. Sem este arquivo, o Spring.NET não poderá funcionar, posto que nele estão todas as funcionalidades necessárias para que o contêiner seja inicializado e que o mesmo reconheça todos os objetos através do parsing, ou seja, o arquivo é totalmente validado antes de ser utilizado
Listagem 5: Configuração do Spring.NET em arquivo de configuração XML
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler
, Spring.Core"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler
,Spring.Core"/>
</sectionGroup>
</configSections>
...
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<!-- Objetos para Injeção de Dependências -->
<objects xmlns="http://www.springframework.net">
<!-- Conexao -->
<object name="Conexao" type="DAL.FonteDeDados.Conexao, DAL"/>
<!-- ContatoDAL -->
<object name="ContatoDAL" type="DAL.Persistencia.ContatoDAL, DAL">
<constructor-arg ref="Conexao"/>
</object>
<!-- ManterContato -->
<object name="ManterContato" type="BLL.Negocio.ManterContato, BLL">
<property name="Dao" ref="ContatoDAL" />
</object>
</objects>
</spring>
...
Dentro da tag configSection no início do arquivo, temos a tag sectionGroup, dentro desta temos mais duas sections com o atributo name, estes atributos significam que neste arquivo temos o acesso ao Contexto e que nele também existem objetos a serem gerenciados pelo Conteiner de Injeção de Dependências. Com relação ao contexto, significa que temos de chamar a interface IApplicationContext dentro de nossa aplicação para que o Spring.NET possa acessar as configurações deste arquivo para iniciar o contêiner de Injeção de Dependências.
Na seção que contêm a tag de nome Spring, temos a configuração e registro dos objetos que serão utilizados pelo contêiner de DI. Veremos este trecho mais de perto através da Listagem 6.
Listagem 6: Seção de Configuração do Spring e seus objetos
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<!-- Objetos para Injeção de Dependências -->
<objects xmlns="http://www.springframework.net">
<!-- Conexao -->
<object name="Conexao" type="DAL.FonteDeDados.Conexao, DAL"/>
<!-- ContatoDAL -->
<object name="ContatoDAL" type="DAL.Persistencia.ContatoDAL, DAL">
<constructor-arg ref="Conexao"/>
</object>
<!-- ManterContato -->
<object name="ManterContato" type="BLL.Negocio.ManterContato, BLL">
<property name="Dao" ref="ContatoDAL" />
</object>
</objects>
</spring>
Nesta seção, a tag context logo abaixo do início da seção completa o que está presente na configSection da Listagem 5, onde temos o atributo chamado object. Ambas context e resource estão interligados a esta configSection.
Com relação aos objetos gerenciados pelo Spring, estes se encontram dentro da tag object que é registrada através de objects, que tem o nome de serviço apontando para HTTP://www.springframework.net, neste momento, iniciando o registro das classes no contêiner de DI do Spring.
Cada tag object contém alguns atributos, sendo os mais importantes name e type. Name recebe um valor qualquer, como uma identificação, ela não precisa ser igual ao nome da classe, mas por convenção o segue apenas para questões de documentação, caso existam muitos em um arquivo de gerenciamento. Já type, somos obrigados a colocar o nome completo da classe, seguido de uma virgula (,) e o nome do assembly, como visto na Listagem 7.
Listagem 7: Um objeto simples registrado
<!-- Conexao -->
<object name="Conexao" type="IntroSpringNet.Persistencia.Conexao, IntroSpringNet"/>
O objeto em questão significa que para o conteiner a classe DAL.FonteDeDados.Conexao no assembly DAL foi registrada com o nome de Conexao.
Caso a tag object só tenha estes registros, significa que é apenas uma classe sendo apontada e nada mais. Porém, quando fazemos as injeções via setter ou via construtor precisamos colocar mais uma tag dentro de object para informar ao Spring que dentro desta classe gerenciada, o contêiner ainda precisa efetuar a Injeção de Dependências. Na Listagem 8, vemos um exemplo de Injeção via Construtor das classes criadas nas listagens 1 e 2.
Listagem 8: Injeção via construtor registrada no arquivo de configuração do Spring.NET
<!-- ClienteDAL -->
<!-- Injeção via Construtor -->
<object name="ClienteDAL" type="IntroSpringNet.Persistencia.ClienteDAL, IntroSpringNet">
<constructor-arg ref="Conexao"/>
</object>
Este objeto registrado na Listagem 8 pela sua implementação nos mostra que não é um objeto simples. Na tag constructor-arg significa que a classe informada tem um construtor e que o parâmetro injetado é a classe registrada com o nome de Conexao, pois ref significa “fazer referência a um objeto registrado no container”. Então, caso a interface IApplicationContext registre o objeto de nome ClienteDAL, ele automaticamente registrará dentro da Classe ClienteDAL, em seu construtor o tipo do argumento será a classe que está atrelada ao nome Conexao e para nosso entendimento é o mesmo objeto registrado na Listagem 7, ou o nosso objeto simples.
A diferença no registro via setter é que ao invés de constructor-arg apenas chamamos a tag property, apontando a propriedade onde a classe é injetada no setter, como nos mostra a Listagem 9.
Listagem 9: Injeção vai Setter registrada no contêiner do Spring.NET
<!-- ManterContato -->
<!-- Injeção via Setter -->
<!-- Injeta ClienteDAL dentro de DAL
DAL é tipada pela interface, logo a mesma é preenchida por ClienteDAL
-->
<object name="ManterCliente" type="IntroSpringNet.Negocio.ManterCliente, IntroSpringNet">
<property name="DAL" ref="ClienteDAL" />
</object>
Este objeto informa que a propriedade DAL receberá a injeção do objeto ClienteDAL mostrado na Listagem 8.
Implementação do Acesso aos Objetos
Agora faremos com que todas estas configurações acima funcionem plenamente. Neste trecho, vamos utilizar a fachada IApplicationContext do Spring para acessar o contêiner de Injeção de Dependências, como no exemplo da Listagem 9.
Listagem 10: Utilizado as configurações na prática
Contato contato = new Contato();
contato.NomeCompleto = "Luis Gabriel Nascimento Simas";
contato.Email = "gabrielsimas@gmail.com";
contato.Linkedin = "http://br.linkedin.com/in/gabrielsimas/";
contato.Twitter = "@gabnascimento";
contato.Facebook = "http://www.facebook.com/luisgabrielsimas";
IApplicationContext di = ContextRegistry.GetContext();
IContatoDAL dal = (ContatoDAL)di.GetObject("ContatoDAL");
dal.Salvar(contato);
Na variável di, lemos o arquivo de configuração, enquanto que na variável dal, carregamos o objeto gerenciável do arquivo de configuração que contém o id contendo o valor “ContatoDAL”, o mesmo objeto da Listagem 8.
Conclusão
Neste artigo bastante introdutório sobre o Spring.NET, vimos um pouco de sua base principal, que é a Injeção de Dependências. Quaisquer dúvidas não hesite em utilizar os fóruns da DevMedia e a seção de comentários abaixo.