Implementação Prática de AOP utilizando Spring.NET

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.

Tags: spring.net AOP dotnet dependency-injection proxy-pattern

Publicado em 8-15 00:29