Compreendendo o Spring AOP a partir de uma perspectiva de configuração XML

Este artigo é compartilhado pela Huawei Cloud Community " Spring Master's Road 18 - Understanding Spring AOP da perspectiva da configuração XML ", autor: Zhuan Yeyang__.

1. Spring AOP e proxy dinâmico

1.1 O relacionamento entre Spring AOP e proxy dinâmico

Spring AOPImplemente programação orientada a aspectos usando proxies dinâmicos como mecanismo principal. Este mecanismo permite Springa criação dinâmica de objetos proxy em tempo de execução. Esses objetos proxy envolvem o objeto de destino (ou seja, componente de negócios) para inserir comportamentos adicionais (como verificações de segurança, gerenciamento de transações, registro em log, etc.) antes e depois de chamar os métodos do objeto de destino. .

  • Proxy dinâmico JDKSpring AOP : O proxy dinâmico usado por padrão quando o objeto de destino implementa uma ou mais interfaces JDK. JDKO proxy dinâmico usa o mecanismo de reflexão para criar um objeto proxy para a interface. Este objeto proxy interceptará todas as chamadas para o método da interface de destino.

  • Proxy CGLIB : Se o objeto de destino não implementar nenhuma interface, Spring AOPele voltará a usar CGLIBa biblioteca para gerar uma subclasse da classe de destino. CGLIB( Code Generation Library) é uma biblioteca poderosa de geração de código de alto desempenho que estende Javaclasses em tempo de execução e substitui métodos em subclasses para implementar a interceptação de métodos.

Independentemente do método proxy utilizado, o objetivo é inserir comportamentos adicionais em diferentes estágios de execução do método por meio de notificações definidas por aspectos, sem alterar o código da lógica de negócio original.

1.2 Terminologia básica do AOP

Aspecto : Aspecto é o núcleo da programação orientada a aspectos. É uma construção que modulariza preocupações em várias classes (como registro, gerenciamento de transações, etc.). Um aspecto pode conter vários tipos de conselhos ( Advice) e um ou mais pontos de corte ( Pointcut) que definem onde e quando esses conselhos são executados.

Ponto de junção : um ponto de junção representa um local específico durante a execução do programa, Spring AOPlimitando esses locais a chamadas de métodos. Simplificando, um ponto de junção é um ponto onde conselhos de aspecto podem ser inseridos.

Conselho : Conselho define a ação a ser executada pelo aspecto no ponto de conexão. Dependendo do tipo de notificação, essas ações podem ser executadas antes, depois que o método é chamado, depois que um resultado é retornado ou quando uma exceção é lançada. Os tipos de notificação incluem:

  • Pré-notificação ( Before advice): executada antes da execução do método.
  • Pós-notificação ( After advice): Executada após a execução do método, independentemente de seus resultados.
  • Notificação pós-retorno ( After-returning advice): Executada após o método ser executado com sucesso.
  • Notificação pós-exceção ( After-throwing advice): executada após o método lançar uma exceção.
  • Conselho surround ( Around advice): executado antes e depois da execução do método, fornecendo controle total sobre as chamadas de método.

Pointcut (Pointcut) : Pointcut é uma expressão. As expressões Pointcut permitem combinar pontos de conexão por meio de nomes de métodos, modificadores de acesso e outras condições, que determinam quais métodos devem ser acionados quando as notificações são executadas.

Objeto alvo : um objeto que é notificado por um ou mais aspectos. Também chamado de objeto com proxy.

Proxy AOP : AOPUm objeto criado pela estrutura para implementar contratos de aspecto (definidos por conselhos e pontos). Em Spring AOP, AOPum proxy pode ser JDKum proxy dinâmico ou CGLIBum proxy.

Introdução : A introdução permite adicionar novos métodos ou propriedades a uma classe existente. Isto é Introduction interfacesconseguido definindo uma ou mais interfaces adicionais ( ), e AOPa estrutura cria um proxy para o objeto de destino que implementa essas interfaces.

Se ainda parecer abstrato, vamos dar outro exemplo de produção cinematográfica como analogia.

Aspecto

Imagine que alguém está filmando um filme e os efeitos especiais do filme (como explosões e efeitos especiais de iluminação) são como preocupações transversais que precisam ser tratadas no aplicativo (como registro ou gerenciamento de transações). Esses efeitos especiais aparecem em muitas cenas diferentes do filme, não apenas em uma cena específica. Em AOPPython, esses “efeitos” são aspectos e podem ser aplicados a várias partes do programa sem alterar a cena (ou código) real.

Ponto de adesão

Continuando com a metáfora do filme, um momento específico de cada cena, como o momento em que ocorre uma explosão, pode ser visto como um ponto de ligação. Na programação, isso geralmente corresponde a uma chamada de método.

Conselho

As notificações são como instruções específicas do diretor para a equipe de efeitos especiais, como “Adicionar um efeito de explosão antes do início da cena” ou “Mostrar o efeito de dissipação de fumaça após o término da cena”. Estas instruções informam à equipe de efeitos especiais quais efeitos específicos devem ser adicionados em momentos específicos do filme. No AOP, essas "instruções" são notificações, especificando que aspectos (efeitos especiais) devem ser executados antes, depois ou próximo a pontos de junção (momentos específicos de execução de código).

Corte pontual

Se o aviso for uma instrução do diretor para a equipe de efeitos especiais, então o ponto de corte serão as condições específicas contidas na instrução, como "cenas noturnas". Os pointcuts definem quais pontos de conexão (como quais chamadas de métodos específicos) devem receber notificações (instruções de efeito).

Objeto alvo

Os objetos alvo são aquelas cenas onde efeitos especiais precisam ser adicionados. Em nossa metáfora de programação, eles são aqueles objetos afetados pela lógica de aspecto (como classes que requerem registro).

Proxy AOP

AOPUm proxy é como uma cópia virtual e controlável de uma cena fornecida pela equipe de efeitos especiais. Esta cópia parece ao público igual à cena original, mas na verdade adiciona automaticamente efeitos especiais quando o diretor precisa deles. Na programação, um proxy é um AOPobjeto criado automaticamente pelo framework. Ele envolve o objeto de destino e garante que as notificações (instruções de efeitos especiais) sejam executadas no momento correto.

Introdução

A introdução é como adicionar um novo personagem ou cena a um filme que não existe no roteiro original. Em AOP, a introdução nos permite adicionar novos métodos ou propriedades a uma classe existente, o que é como estender o conteúdo de um filme sem alterar o roteiro original.

2. Implemente Spring AOP por meio de configuração XML

SpringFornece AOPsuporte avançado e pode XMLdefinir aspectos, notificações ( advice) e pontos de corte ( pointcuts) por meio da configuração. Isso permite adicionar comportamentos adicionais (como registro em log, gerenciamento de transações etc.) sem modificar o código-fonte.

Etapas de implementação:

  1. Adicionar dependências do Springpom.xml : adicione Springestrutura e AOPdependências relacionadas ao projeto .

  2. Definir interfaces de negócios e classes de implementação : Crie interfaces lógicas de negócios e suas implementações, como uma classe de serviço simples.

  3. Definir classes de aspecto : crie uma classe de aspecto para definir notificações pré, pós e finais.

  4. Configuração XML : applicationContext.xmlConfigure aspectos, negócios beane AOPtags relacionadas em XML.

2.1 Adicionar dependência Spring

No pom.xmlarquivo, adicione as seguintes dependências

<dependências>
    <dependência>
        <groupId>org.springframework</groupId>
        <artifactId>contexto de primavera</artifactId>
        <versão>5.3.10</versão>
    </dependency>
    <dependência>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <versão>5.3.10</versão>
    </dependency>
    <dependência>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <versão>1.9.6</versão>
    </dependency>
</dependências>

2.2 Definir interfaces de negócios e classes de implementação

Primeiro, definimos uma interface lógica de negócios MyServicee sua implementação MyServiceImpl.

MeuServiço.java:

pacote com.example.demo.aop;
interface pública MeuServiço {
    String performAction (String input) lança exceção;
}

MeuServiceImpl.java:

pacote com.example.demo.aop;
classe pública MyServiceImpl implementa MyService {
    @Sobrepor
    public String performAction(String ação) lança exceção {
        System.out.println("Executando ação em MyService: " + action);
        if ("lançar".equals(ação)) {
            throw new Exception("Exceção do MyService");
        }
        return "Ação realizada: " + ação;
    }
}

2.3 Definir classes de aspecto

A seguir, definimos uma classe de aspecto MyAspectque conterá um pré-conselho ( advice) que é executado antes da execução MyServicedo método.performAction

MeuAspect.java:

pacote com.example.demo.aop;

importar org.aspectj.lang.ProceedingJoinPoint;

classe pública MeuAspecto {

    //pré-notificação
    public void beforeAdvice() {
        System.out.println("Antes que o conselho seja executado!");
    }

    //postar notificação
    public void afterAdvice() {
        System.out.println("Depois que o conselho estiver em execução!");
    }

    //Notifica após retorno
    public void afterReturningAdvice(Object retVal) {
        System.out.println("Após retornar o conselho está em execução! Valor de retorno: " + retVal);
    }

    //Notificação após exceção
    public void afterThrowingAdvice(Throwable ex) {
        System.out.println("Depois de lançar o conselho está em execução! Exceção: " + ex.getMessage());
    }

    //notificação surround
    objeto público aroundAdvice (ProceedingJoinPoint joinPoint) lança Throwable {
        System.out.println("Sobre conselhos: Antes da execução do método");
        Resultado do objeto = null;
        tentar {
            resultado = joinPoint.proceed();
        } finalmente {
            System.out.println("Sobre conselhos: Após a execução do método");
        }
        resultado de retorno;
    }
}

2.4 XML de configuração

Finalmente, precisamos configurar o conteúdo acima e relacionado no Springarquivo de configuração .applicationContext.xmlbeanAOP

aplicaçãoContext.xml:

<?xml versão="1.0" codificação="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
O texto acima é a declaração de cabeçalho do arquivo XML, que define a versão e o tipo de codificação do arquivo e apresenta o namespace dos beans Spring e AOP.
Através desses namespaces, podemos usar tags <bean> e <aop:*> em XML.
-->
    <!-- Definições de feijão -->
    <bean id="myService" class="com.example.demo.aop.MyServiceImpl"/>
    <bean id="myAspect" class="com.example.demo.aop.MyAspect"/>
	<!-- Configuração AOP-->
    <aop:config>
        <!-- Definir aspectos e suas notificações -->
        <aop:aspect id="myAspectRef" ref="myAspect">
            <!-- Defina pointcuts e especifique notificações que devem ser acionadas quando os métodos são executados -->
            <aop:pointcut id="serviceOperation" expressão="execution(* com.example.demo.aop.MyService.performAction(..))"/>
            <!-- Aplicar pré-notificação, especificar operações antes da execução do método -->
            <aop:before method="beforeAdvice" pointcut-ref="serviceOperation"/>
            <!-- Aplicar pós-notificação, especificar a operação após a execução do método, se o método foi executado com sucesso ou se uma exceção foi lançada -->
            <aop:after method="afterAdvice" pointcut-ref="serviceOperation"/>
            <!-- Notificação após o retorno do aplicativo, operações após o método especificado ser executado e retornado com sucesso -->
            <aop:after-returning method="afterReturningAdvice" pointcut-ref="serviceOperation" return="retVal"/>
            <!-- Notificação após exceção do aplicativo, ação após o método especificado lançar exceção -->
            <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="serviceOperation" throw="ex"/>
            <!-- Aplique notificações circundantes para fornecer controle completo antes e depois da execução do método -->
            <aop:around method="aroundAdvice" pointcut-ref="serviceOperation"/>
        </aop:aspecto>
    </aop:config>
</feijão>

myService : Esta é a lógica de negócios beane aponta para MyServiceImpluma instância da classe.

myAspect : Este é o aspecto bean, apontando para MyAspectuma instância da classe.

<aop:config>: Este é AOPo elemento raiz da configuração. Todas AOPas configurações, incluindo definições de aspecto, pointcuts e métodos de notificação, precisam ser definidas dentro deste elemento.

Aspecto : Definido através <aop:aspect>de elementos, contém uma série de conselhos ( advice) e um ou mais pontos de corte ( pointcut). Este elemento associa classes de aspecto (classes que contêm lógica de notificação) a operações específicas (como e quando aprimorar o objeto alvo).

Pointcut : por meio <aop:pointcut>da definição do elemento, pointcut é especificado pela expressão. Quando você precisa controlar com precisão quais métodos irão disparar notificações quando executados, você precisa definir pointcut. Expressões pointcut podem especificar métodos com muita precisão, por exemplo, por nome de método, tipos de parâmetros, anotações, etc. expressionEle define a expressão do pointcut e especifica as regras de correspondência do pointcut. A expressão aqui execution(* com.example.demo.aop.MyService.performAction(..))significa que o pointcut corresponde à execução do método MyServicena interface performActione o pointcut é usado para especificar em quais pontos de conexão ( Join Pointcomo chamadas de método) a notificação é aplicada.

Sobre análise de expressõesexecution(* com.example.demo.aop.MyService.performAction(..))

execução : é a função pointcut mais comumente usada, usada para combinar os pontos de conexão da execução do método.

*: Indica que o tipo de retorno do método é arbitrário.

com.example.demo.aop.MyService.performAction : especifica o caminho completo do nome da interface e do nome do método.

(…) : Indica que os parâmetros do método são arbitrários e corresponderão independentemente de quantos parâmetros o método possui.

  • Ponto de junção : um ponto de junção refere-se a um determinado ponto durante a execução do programa, como uma chamada de método. Os pontos de junção são identificados e correspondidos  por expressões pointcut( ), que definem um pointcut que especifica um conjunto explícito de pontos de junção - ou seja, todas as invocações de métodos da interface . Neste exemplo, as chamadas de método de interface são pontos de conexão potenciais. Cada vez que um método é chamado, um ponto de junção é alcançado . Este ponto de conexão é onde o aplicativo é notificado sobre seu tempo.Pointcutexecution(* com.example.demo.aop.MyService.performAction(..))MyServiceperformActionMyServiceperformActionperformAction

  • Conselho : Esta é uma AOPação que aprimora a execução de um método realizando ações em momentos específicos. methodO atributo especifica o nome do método do aspecto que deve ser executado quando o pointcut corresponder, pointcut-refreferenciando o pointcut definido acima. Por exemplo, aqui está o método que é chamado antes da execução beforeAdvicedo método de destino . performActionIsso significa que sempre que MyService.performAction(..)um método for chamado, beforeAdviceo método será executado primeiro.

Resumindo em uma frase: Spring AOPAo definir regras (pontos de corte) em aspectos para especificar quando (pontos de conexão) e como (notificações) aprimorar métodos específicos, a modularização do código e a separação de interesses são alcançadas sem modificar a lógica de negócios original .

Dessa forma, Spring AOP você pode definir uma lógica personalizada a ser inserida antes, depois ou próximo à execução de um método específico sem modificar o código da lógica de negócios original. Este é um mecanismo poderoso para alcançar a separação de interesses, especialmente para interesses transversais que abrangem múltiplas partes da aplicação (como registro, gerenciamento de transações, etc.).

Observe que se <aop:config>definido como

<aop:config proxy-target-class="true">
    <!--Outra configuração permanece inalterada-->
</aop:config>

Definir isso proxy-target-class="true"fará com que o proxy Spring AOPseja usado preferencialmente, CGLIBmesmo que o objeto de destino implemente a interface. Por padrão, proxy-target-classa propriedade não precisa ser definida ou, se estiver definida false, um proxy dinâmico será usado JDK.

Programa principal:

DemoApplication.java:

pacote com.example.demo;

importar com.example.demo.aop.MyService;
importar org.springframework.context.support.ClassPathXmlApplicationContext;

classe pública DemoApplication {
    public static void main(String[] args) {
        Contexto ClassPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        MeuServiço meuServiço = (MeuServiço) context.getBean("meuServiço");

        tentar {
            System.out.println(myService.performAction("normal"));
        } catch (Exceção e) {
            e.printStackTrace();
        }

        System.out.println("======================");

        tentar {
            System.out.println(myService.performAction("throw"));
        } catch (Exceção e) {
            System.out.println("Exceção capturada em main: " + e.getMessage());
        }

        contexto.close();
    }
}

resultado da operação:

Ao combinar a tecnologia de proxy dinâmico com esses AOPconceitos, Spring AOPos aplicativos podem receber suporte para preocupações transversais de uma forma não intrusiva, permitindo que os desenvolvedores modularizem essas preocupações e mantenham os componentes da lógica de negócios focados e simples.

Se você estiver interessado no proxy dinâmico, poderá depurá-lo novamente. JDKO proxy dinâmico aqui é porque public class MyServiceImpl implements MyService a interface é implementada da seguinte forma:

Vamos falar brevemente sobre as principais classes e interfaces que podem ser vistas aqui.

ProxyFactory : Esta é Spring AOPuma classe de fábrica usada para criar objetos proxy. Ele pode decidir usar JDKproxy dinâmico ou proxy com base no fato de o objeto de destino implementar a interface CGLIB.

AopProxy : Esta interface define métodos para obter objetos proxy. Possui duas implementações principais: JdkDynamicAopProxy(para JDKproxies dinâmicos) e CglibAopProxy(para CGLIBproxies).

JdkDynamicAopProxy : implementa AopProxya interface e usa JDKtecnologia de proxy dinâmico para criar um proxy. Ele implementa InvocationHandlera interface e intercepta todas as chamadas de método para o objeto proxy.

CglibAopProxy : Também implementa AopProxya interface, mas usa CGLIBuma biblioteca para criar objetos proxy. Para classes que não implementam a interface, Springeste método será escolhido para criar o proxy.

Se quiser entender Spring AOPo código-fonte em profundidade, você pode visualizar diretamente JdkDynamicAopProxya CglibAopProxyimplementação dessas duas classes. Este não é o foco deste artigo, apenas mencione brevemente:

Por exemplo, JdkDynamicAopProxyveja a implementação do proxy dinâmico em:

  1. JdkDynamicAopProxyAs classes implementam InvocationHandlerinterfaces, que são JDKo núcleo do proxy dinâmico. Em seu invokemétodo, haverá lógica para determinar se a chamada precisa ser interceptada, e as notificações correspondentes serão aplicadas antes e depois da chamada.

  2. O processo de criação de um proxy é feito principalmente ProxyFactoryatravés da chamada de createAopProxy()um método, que retorna uma instância de JdkDynamicAopProxyou de acordo com a configuração CglibAopProxy.

  3. Uso de proxy: o código do cliente ProxyFactoryobtém o objeto proxy e chama o método de destino por meio desse objeto proxy. O objeto proxy usa JdkDynamicAopProxyor internamente CglibAopProxypara interceptar essas chamadas e AOPrealizar notificações com base na configuração. O processo de obtenção ProxyFactoryde um objeto proxy Springgeralmente é feito implicitamente na configuração e uso, principalmente quando se utiliza Springgerenciamento de contêineres AOP. Este processo não exige que o desenvolvedor chame ProxyFactorya classe diretamente. Quando Springum é definido na configuração beane um aspecto é aplicado a ele, Springo contêiner cuida automaticamente do processo de criação do agente e aplicação de notificações. Isto é conseguido através do suporte Springao pós-processador e AOPao namespace, e os desenvolvedores geralmente só precisam configurar aspectos e conselhos de forma declarativa.

Se você quiser ver CGLIBo agente, aqui 2está uma maneira

O terceiro 1método é remover a interface MyServiceImplimplementada e, em seguida , alterar o local correspondente entre MyServiceo programa principal e a expressão . A terceira maneira é definir explicitamente as propriedades do rótulo no arquivo de configuração para conseguir isso. do seguinte modo:expressionMyServiceImpl
2Spring<aop:config>proxy-target-class="true"

<aop:config proxy-target-class="true">
    <!--Outra configuração permanece inalterada-->
</aop:config>

A depuração é a seguinte:

 

Bem-vindo à conexão tripla com um clique ~

Se você tiver alguma dúvida, deixe uma mensagem e vamos discutir e aprender juntos.

Clique para seguir e conhecer as novas tecnologias da Huawei Cloud o mais rápido possível~

 

RustDesk suspendeu o serviço doméstico Taobao (taobao.com) devido a fraude desenfreada, reiniciou o trabalho de otimização da versão web, a Apple lançou o chip M4, estudantes do ensino médio criaram sua própria linguagem de programação de código aberto como uma cerimônia de maioridade - Internautas comentaram: Confiando em a defesa, Yunfeng renunciou ao Alibaba e planeja produzir no futuro o destino para programadores de jogos independentes o Visual Studio Code 1.89, é oficialmente anunciado pela Huawei. O ajuste de trabalho de Yu Chengdong foi pregado no “Pilar da Vergonha FFmpeg. ” 15 anos atrás, mas hoje ele tem que nos agradecer - Tencent QQ Video vinga sua vergonha anterior? A estação espelho de código aberto da Universidade de Ciência e Tecnologia Huazhong está oficialmente aberta ao acesso à rede externa
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/u/4526289/blog/11106069
Recomendado
Clasificación