Configuração XML do Spring AOP

Este artigo demonstra como configurar a Programação Orientada a Aspectos (AOP) no Spring Framwork utilizando exclusivamente configuração XML.

Considere o seguinte cenário para exemplos:

Interafce e Implementação do DAO

Primeiro, definimos uma interface para o DAO de Usuário e sua implementação concreta.

package com.exemplo.persistencia;

import com.exemplo.modelo.Usuario;

public interface UsuarioDAO {
    void registrar(Usuario usuario);
}

package com.exemplo.persistencia.impl;

import org.springframework.stereotype.Component;
import com.exemplo.persistencia.UsuarioDAO;
import com.exemplo.modelo.Usuario;

@Component
public class UsuarioDAOImpl implements UsuarioDAO {

    @Override
    public void registrar(Usuario usuario) {
        // Lógica de persistência (ex: Hibernate, JDBC)
        System.out.println("Usuário registrado com sucesso!");
    }
}

Classe Aspecto (Aspect)

Criamos uma classe que conterá a lógica transversal (cross-cutting concern), como logging.

package com.exemplo.aspectos;

public class InterceptadorLog {

    public void aconselharAntes() {
        System.out.println("[Log] Antes da execução do método.");
    }
}

Serviço de Aplicação

A classe de serviço utiliza a injeção de dependência para consumir o DAO.

package com.exemplo.servico;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.exemplo.persistencia.UsuarioDAO;
import com.exemplo.modelo.Usuario;

@Component("servicoUsuario")
public class ServicoUsuario {

    private UsuarioDAO usuarioDAO;

    @Autowired
    public void setUsuarioDAO(UsuarioDAO usuarioDAO) {
        this.usuarioDAO = usuarioDAO;
    }

    public void adicionar(Usuario usuario) {
        usuarioDAO.registrar(usuario);
    }
}

Configuração XML (Exemplo 1: Pointcut Global)

No arquivo applicationContext.xml, declaramos um pointcut reutilizável dentro do bloco <aop:config> e referenciamos-o no conselho (advice).

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.exemplo"/>

    <!-- Registra a classe de aspecto como um bean -->
    <bean id="logAspecto" class="com.exemplo.aspectos.InterceptadorLog"/>

    <aop:config>
        <!-- Define um pointcut global chamado 'pontoServico' -->
        <aop:pointcut id="pontoServico"
                      expression="execution(public * com.exemplo.servico..*.adicionar(..))"/>

        <!-- Associa o aspecto ao pointcut -->
        <aop:aspect id="aspectoLog" ref="logAspecto">
            <aop:before method="aconselharAntes" pointcut-ref="pontoServico"/>
        </aop:aspect>
    </aop:config>

</beans>

Configuração XML (Exemplo 2: Pointcut Inline)

Alternativamente, o pointcut pode ser definido diretamente dentro do elemento do conselho, tornando-o local àquele aspecto.

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.exemplo"/>

    <bean id="logAspecto" class="com.exemplo.aspectos.InterceptadorLog"/>

    <aop:config>
        <aop:aspect id="aspectoLog" ref="logAspecto">
            <!-- Pointcut inline, definido apenas para este conselho -->
            <aop:before method="aconselharAntes"
                        pointcut="execution(public * com.exemplo.servico..*.adicionar(..))"/>
        </aop:aspect>
    </aop:config>

</beans>

Teste

Um teste de integração verifica o comportamento da aplicação.

package com.exemplo;

import com.exemplo.modelo.Usuario;
import com.exemplo.servico.ServicoUsuario;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

class AplicacaoTest {

    @Test
    void deveExecutarLogAntesDoServico() {
        ClassPathXmlApplicationContext contexto =
                new ClassPathXmlApplicationContext("applicationContext.xml");

        ServicoUsuario servico = contexto.getBean(ServicoUsuario.class);
        servico.adicionar(new Usuario());

        contexto.close();
    }
}

Ao executar o teste, o console exibirá a mensagem do log ([Log] Antes da execução do método.) antes da mensagem de registro do DAO.

Nota: A configuração de <aop:advisor> é frequentmeente utilizada em conjunto com a transação declarativa do Spring, geralmente configurada via namespace tx.

Tags: Spring AOP XML Pointcut Aspect

Publicado em 6-9 19:39 por Thomas