O framwork Spring.NET adapta os padrões de desenvolvimento enterprise da plataforma Java para o ecossistema .NET, ofereecndo funcionalidades robustas para gerenciamento de aplicações. Assim como suas contrapartes em outras linguagens, sua arquitetura baseia-se fortemente no núcleo Spring Core, estendendo-se para camadas superiores como a programação orientada a aspectos (AOP) e integração com persistência de dados.
A principal vantagem dessa abordagem reside na capacidade de separar preocupações transversais — como logging, segurança e transações — da lógica de negócios principal. Enquanto a Orientação a Objetos foca nas entidades, o AOP permite modularizar comportamentos que afetam múltiplos componentes sem poluir o código fonte original.
Além do AOP, o Spring.NET implementa o conceito de Inversão de Controle (IoC) ou Injeção de Dependência (DI), permitindo que os componentes sejam definidos declarativamente e montados pelo contêiner em tempo de execução.
Cenário de Exemplo
Para demonstrar a configuração de um ponto de intersecção (joinpoint), criaremos um cenário onde interceptamos uma chamada de método antes da sua execução. Utilizaremos uma estrutura de bibliotecas dividida entre serviços de negócio e aspectos transversais.
1. Biblioteca de Negócios (Application.Services)
Começamos definindo um contrato de serviço que representa uma operação genérica, como a autenticação de um usuário.
using System;
namespace Application.Services
{
public interface IAutenticacaoServico
{
bool ValidarCredenciais(string usuario, string senha);
}
}
A implementação concreta contém apenas a lógica de domínio:
using System;
namespace Application.Services
{
public class ServicoAutenticacao : IAutenticacaoServico
{
public bool ValidarCredenciais(string usuario, string senha)
{
Console.WriteLine($"Tentativa de login para: {usuario}");
return true; // Simulação bem-sucedida
}
}
}
2. Definição do Aspecto (Application.CrossCutting)
No projeto de cortes transversais, precisamos implementar uma classe que atenda à intefrace IMethodBeforeAdvice. Esta ação será executada sempre que um método alvo for invocado.
using System.Reflection;
using Spring.Aop.Framework;
namespace Application.CrossCutting
{
public class LoggingAntesDeExecucao : IMethodBeforeAdvice
{
public void Before(MethodInfo metodo, object[] argumentos, object target)
{
Console.WriteLine("[LOG] Interceptando: " + metodo.Name);
Console.WriteLine("[LOG] Classe Alvo: " + target.GetType().FullName);
if (argumentos != null)
{
foreach (var item in argumentos)
{
Console.WriteLine($"[ARG] Valor: {item}");
}
}
}
}
}
3. Configuração do Contêiner (app.config)
O comportamento do Spring é controlado através de arquivos de configuração. Aqui mapeamos os objetos, vinculamos o aspecto ao serviço real usando um Proxy Factory e registramos o contexto de aplicação.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<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>
<objects xmlns="http://www.springframework.net">
<description>Configuração AOP para Autenticação</description>
<!-- Registro do Advice -->
<object id="loggingAdvice" type="Application.CrossCutting.LoggingAntesDeExecucao, Application.CrossCutting"/>
<!-- Definição do Proxy -->
<object id="autenticacaoProxy" type="Spring.Aop.Framework.ProxyFactoryObject">
<property name="Target">
<object type="Application.Services.ServicoAutenticacao, Application.Services"/>
</property>
<property name="InterceptorNames">
<list>
<value>loggingAdvice</value>
</list>
</property>
<property name="Interfaces">
<value>Application.Services.IAutenticacaoServico, Application.Services</value>
</property>
</object>
</objects>
</spring>
</configuration>
4. Execução da Aplicação
No aplicativo de console de entrada, recuperamos a instância gerida pelo contexto de aplicação. Ao chamar o método configurado, o framework injeta automaticamente a lógica de log antes de passar o fluxo para o serviço original.
using System;
using Spring.Context;
using Spring.Context.Support;
namespace Demo.ConsoleRunner
{
class Program
{
static void Main(string[] args)
{
IApplicationContext contexto = ContextRegistry.GetContext();
IAutenticacaoServico servico =
(IAutenticacaoServico)contexto.GetObject("autenticacaoProxy");
// A chamada abaixo dispara o Advice antes do método real
servico.ValidarCredenciais("admin_user", "senha123");
Console.ReadKey();
}
}
}
Ao executar este programa, a saída no console mostrará primeiramente as informações registradas pelo Advice, seguida pela mensagem definida dentro da classe de serviço.