Análise do princípio SpringAOP

Existem basicamente dois módulos principais no Spring, um dos quais é AOP (Aspect Programming). Normalmente, quando usamos a versão de anotação SpringAOP, definimos uma classe de aspecto, definimos o ponto de entrada e, em seguida, o ponto de entrada definido pode ser processado por @Before pré-notificação, @After processamento pós-notificação, @AfterReturning processamento de notificação de retorno, @AfterThrowing o processamento de notificação de exceção, @Around envolve o processamento de notificação e, finalmente, adiciona a anotação @EnableAspectJAutoProxy à classe de configuração (ou geralmente nossa classe de inicialização no SpringBoot), para que nossa configuração AOP no Spring seja configurada.

 O que a anotação @EnableAspectJAutoProxy faz?

Como o nome sugere, essa anotação é o significado de abrir a programação de aspecto AOP. Muitas anotações como @EnableXXX são usadas no SpringBoot. A maioria dessas anotações é usada para ativar uma determinada função. Na verdade, a maioria delas vem com anotações @Import. . A função da anotação @Import é importar um componente para o contêiner IOC. Existem três maneiras de importar componentes

  1. Importar na forma de um objeto de classe, como @Import (Car.Class) Isso é equivalente a importar um objeto Car para o contêiner
  2. Personalize uma classe herdada de ImportSelect, substitua o método selectImports interno para retornar o nome completo da classe do componente que precisa ser importado para o contêiner
  3. Personalize uma classe herdada de ImportBeanDefinitionRegistrar, reescreva o método registerBeanDefinitions dentro e use o parâmetro BeanDefinitionRegistry.registerBeanDefinition ("book", new RootBeanDefinition (Book.class)) para importar o componente para o contêiner,

 Em seguida, clicamos na anotação @EnableAspectJProxy para dar uma olhada

Com certeza, a anotação @Import também é usada internamente e, em seguida, observe as classes na anotação @Import

Pode-se verificar que a terceira forma é usada para importar os componentes, então qual bean é importado aqui? Vamos nos aprofundar no método registerAspectJAnnotationAutoProxyCreatorIfNecessary

Portanto, podemos saber aqui que o componente importado é a classe AnnotationAwareAspectJAutoProxyCreator e seu id é org.springframework.aop.config.internalAutoProxyCreator.

O que AnnotationAwareAspectJAutoProxyCreator faz?

1. Registre AnnotationAwareAspectJAutoProxyCreator

Em primeiro lugar, precisamos saber o papel desta classe, primeiro vá para esta classe para olhar sua estrutura de herança, para ver se esta classe herda algumas classes especiais para que haja tratamentos especiais quando o container Spring é inicializado.

Vá para esta classe e descubra que o nível de herança desta classe é mais alto. A estrutura de herança desta classe é fornecida abaixo:

AnnotationAwareAspectJAutoProxyCreator
-> AspectJAwareAdvisorAutoProxyCreator
  -> AbstractAdvisorAutoProxyCreator
    -> AbstractAutoProxyCreator (上面 还有 父 类)
      implementa SmartInstantiationAwareBeanPostProcessor , BeanFactoryAware

Pode-se descobrir que duas interfaces também são implementadas em sua classe pai AbstractAutoProxyCreator. Eles são SmartInstantiationAwareBeanPostProcessor relacionados à inicialização do Bean e BeanFactoryAware relacionados à inicialização do BeanFactory. Então, podemos encontrar os métodos dessas duas interfaces em AnnotationAwareAspectJAutoProxyCreator e sua classe pai e atingir um ponto de interrupção pelo caminho. Podemos descobrir que a classe AbstractAdvisorAutoProxyCreator reescreve o método setBeanFactory de BeanFactoryAware e, em seguida, chama um método initBeanFactory, que também é sobrescrito pela classe AnnotationAwareAspectJAutoProxyCreator, então definimos um ponto de interrupção em setBeanFactory de AbstractAdvisorAutoProxyCreator, e O método postProcessBeforeInstantiation de AbstractAutoProxyCreator é interrompido. Então podemos depurar para ver como os métodos são chamados.

Assim que iniciamos o projeto, descobrimos que o programa veio para o método setBeanFactory, e então podemos olhar a pilha de chamadas do método no canto esquerdo inferior para ver como chegar ao método setBeanFactory passo a passo.

Em primeiro lugar, precisamos inicializar nosso contêiner no início, então chegamos ao método de atualização para atualizar o contêiner.

No método de atualização, existe um método usado para registrar o BeanPostProcessor, que na verdade é o processo de criar um objeto BeanPostProcessor e armazená-lo no container. E a classe AnnotationAwareAspectJAutoProxyCreator com a qual estamos preocupados também implementa indiretamente a interface BeanPostProcessor, então o trabalho interno tem um ótimo relacionamento com nosso AnnotationAwareAspectJAutoProxyCreator.

Em seguida, até o método registerBeanPostProcessors de PostProcessorRegistrationDelegate, podemos colocar um ponto de interrupção neste método para ver o que o trabalho é feito dentro:

Vá para a primeira etapa para obter o nome completo da classe de todos os BeanPostProcessor

A próxima lógica é quase a mesma, que é fazer com que a instância BeanPostProcessor determine a prioridade. Como nosso AnnotationAwareAspectJAutoProxyCreator implementa a interface Ordered, chegamos ao ramo de julgamento de Ordered e adicionamos o nome completo da classe do BeanPostProcessor que pertence a Ordered to the Ordered. Na coleção List, o seguinte é a instância BeanPostProcessor correspondente à inicialização da travessia da coleção, que se refere especificamente a AnnotationAwareAspectJAutoProxyCreator

Em seguida, aprofundamos no método beanFactory.getBean, chegamos ao método doCreateBean () e o executamos no método initializeBean

Mergulhe neste método

Então, isso chega ao ponto onde interrompemos, podemos olhar as seguintes operações de inicialização e terminar todo o método initializeBean.

Finalmente, adicione cada BeanPostProcessor ao BeanFactory

Neste ponto, o processo de registro de AnnotationAwareAspectJAutoProxyCreator provavelmente acabou. Vamos resumir o processo de registro de AnnotationAwareAspectJAutoProxyCreator:

  1. Obtenha os nomes de classe completos de todos os BeanPostProcessors que foram definidos no contêiner IOC, incluindo os componentes AnnotationAwareAspectJAutoProxyCreator que precisam ser importados para nossa anotação @EnableAspectJAutoProxy
  2. Adicione outro BeanPostProcessor ao contêiner
  3. Registre o BeanPostProcessor que implementa a interface PriorityOrdered primeiro
  4. Em seguida, registre o BeanPostProcessor que implementa a interface Ordered
  5. Finalmente registre o BeanPostProcessor comum
  6. Chame o método getBean para registrar (criar) o objeto BeanPostProcessor de acordo com o nome completo da classe e salvá-lo no contêiner. Isso se refere especificamente à criação do AnnotationAwareAspectJAutoProxyCreator BeanPostProcessor. Neste processo, inclui a criação de uma instância Bean, populateBean () -> dando vários atributos ao Bean Atribuição, lidar com o retorno de chamada da interface Aware, aplicar postProcessBeforeInitialization (), executar um método init personalizado, aplicar postProcessAfterInitialization () do pós-processador
  7. Adicione o BeanPostProcessor registrado ao BeanFactory -> beanFactory.addBeanPostProcessor (postProcessor)

2. A função de AnnotationAwareAspectJAutoProxyCreator

Acima falamos sobre o processo de registro (criação) de AnnotationAwareAspectJAutoProxyCreator no contêiner, então qual é o efeito de criar este componente? Na verdade, podemos descobrir que esta classe é indiretamente a classe de implementação da interface InstantiationAwareBeanPostProcessor, e esta interface herda a interface BeanPostProcessor

Portanto, o AnnotationAwareAspectJAutoProxyCreator que criamos é um BeanPostProcessor de InstantiationAwareBeanPostProcessor, e qual é a função especial do BeanPostProcessor que implementa essa interface? Na verdade, quando o método Spring refresh inicializa o contêiner, uma etapa é inicializar o método Bean restante. Esse método é para inicializar nossas classes personalizadas usuais. Vejamos este método abaixo, porque ao inicializar essas classes , BeanPostProcessor que implementa a interface InstantiationAwareBeanPostProcessor funcionará nele.

Reescrevemos o método postProcessBeforeInstantiation da interface InstantiationAwareBeanPostProcessor em AbstractAutoProxyCreator e colocamos um ponto de interrupção para ver por quais métodos esse processo passou

O primeiro que vem é o método finishBeanFactoryInitialization no método de atualização.

 Vá até o método getBean

Vá em frente e siga o seguinte método

Se o bean retornado pelo método resolveBeforeInstantiation não for nulo, retorne diretamente e a criação for bem-sucedida, caso contrário, use o método doCreateBean para criar o bean

Vamos nos aprofundar no método resolveBeforeInstantiation

Método applyBeanPostProcessorsBeforeInstantiation aprofundado

Você pode ver que esta é a função da interface InstantiationAwareBeanPostProcessor. Antes de criar uma instância Bean, você obterá todos os BeanPostProcessors primeiro. Se o BeanPostProcessor atravessado implementa a interface InstantiationAwareBeanPostProcessor, então use este BeanPostProcessor para chamar seu método reescrito postProcessantiationBeforeIn Tente retornar uma instância Bean, se puder retornar, então retorne diretamente, se o retorno for nulo, então use doCreateBean (este processo é consistente com o processo de criação de BeanPostProcessor acima) para criar uma instância Bean. Portanto, aqui também podemos saber que os componentes que implementam diretamente a interface BeanPostProcessor funcionarão antes e depois de todas as instâncias do Bean serem criadas, e os componentes que implementam a interface InstantiationAwareBeanPostProcessor terão uma interceptação antes que todas as instâncias do Bean sejam criadas, que é para tentar retornar o Bean Instância. Em outras palavras, nosso AnnotationAwareAspectJAutoProxyCreator tentará retornar um objeto proxy antes que todas as outras instâncias do Bean sejam criadas.

3. Crie um objeto proxy AOP

Como iremos passar pelo método postProcessBeforeInstantiation de AbstractAutoProxyCreator (a classe pai de AnnotationAwareAspectJAutoProxyCreator) para tentar obter uma instância antes de criar uma instância Bean, vamos dar uma olhada neste método aqui.

Uma vez que estamos aqui para ver a criação de objetos AOP, colocamos o ponto de interrupção para a criação desses objetos AOP, vamos falar sobre a classe AOP do Demo primeiro

Objetos a serem procurados:

Método de aprimoramento:

Classe de configuração:

Bem, o acima é sobre a classe AOP, continuamos a olhar para o método postProcessBeforeInstantiation de AbstractAutoProxyCreator

Primeiro, determine se o bean que precisa ser inicializado está em adviseBeans e, em segundo lugar, determine se o bean é um tipo básico de Advice, PointCut, Advisor, AopInfrastructureBean ou Aspect. Se a classe que vamos inicializar é o Calculate que precisa ser aprimorado, retornaremos False, porque esta classe não é um dos tipos acima.

Há também um método shouldSkip, que foi reescrito por AnnotationAwareAspectJAutoProxyCreator

O método shouldSkip da classe pai AbstractAutoProxyCreator retorna falso diretamente

Portanto, em resumo, o resultado da chamada shouldSkip aqui deve sempre retornar falso.

Então olhe para o seguinte julgamento

Como null é retornado, nosso contêiner precisa criar este Bean. Depois de criar este Bean, ele passará pelo método postProcessAfterInitialization de nosso BeanPostProcessor (AbstractAutoProxyCreator)

A lógica principal dele está no método wrapIfNecessary.Este método é principalmente para criar objetos proxy, então vamos entrar e ver como ele é criado.

Então olhe abaixo

Aqui está um para encontrar todos os intensificadores que podem ser aplicados ao Bean criado atualmente, dê uma olhada mais de perto

 Acima, temos todos os intensificadores aplicáveis ​​e, em seguida, olhamos para

O ponto principal é o método createProxy. Você pode ver pelo nome que este é o método para criar um objeto proxy. Vamos dar uma olhada mais de perto.

Aprofundando-se no método de retorno do objeto proxy, vá para o método createAopProxy

No final, o que obtemos é um objeto proxy dinâmico criado por cglib ou jdk. O resumo do processo é que no processo de criação de um proxy AOP, depois de inicializarmos o Bean (método postProcessAfterInitialization), encontraremos o método de aprimoramento correspondente de acordo com o Bean e, se houver um método de aprimoramento correspondente, criaremos um proxy dinâmico para o objeto. Objeto, se não houver nenhum objeto, retorna o objeto diretamente, então o que obtemos no container depois é o objeto proxy deste componente.

4. Obtenha a cadeia de interceptor MethodInterceptor

Primeiro, vamos colocar uma depuração de ponto de interrupção no método que o destino precisa ser aprimorado.

Você pode ver que um método de interceptação chegou neste momento. Ouvindo o nome, você provavelmente sabe que este método é para interceptar a execução do método de destino. O foco está na lógica de criação de uma cadeia de interceptores abaixo.

A seguir, veremos principalmente como a cadeia de interceptores é criada e inserimos o método de criação de uma cadeia de interceptores

Aqui estão apenas algumas lógicas sobre o cache, a principal criação da cadeia de interceptores é o método getInterceptorsAndDynamicInterceptionAdvice, insira o método

Em primeiro lugar, podemos ver que a lógica principal está neste loop for e a coleção de orientadores é percorrida.Nesta coleção, há um ExposeInvocationInterceptor padrão e nossos 4 realçadores. E então é provável que converta cada conselheiro em um interceptador

Se for um tipo MethodInterceptor, adicione-o à coleção; do contrário, use o AdvisorAdapter correspondente para convertê-lo em um MethodInterceptor e adicioná-lo à coleção. Portanto, atravesse cada consultor e, em seguida, cada consultor obterá a matriz de cadeia de interceptor correspondente e, em seguida, colocará a matriz no contêiner de interceptor.

5. Método de notificação de chamada em cadeia

Então, temos a cadeia de interceptores acima, como chamar o método de notificação nesta cadeia de interceptores? Do exposto, sabemos que quando a cadeia de interceptores que obtemos não está vazia, ou seja, há um método aprimorado atuando no método de destino, um novo CglibMethodInvocation é necessário para chamar proceda para executar o método aprimorado. Vamos dar uma olhada em como este método de procedimento é executado

Em primeiro lugar, o acima é para primeiro determinar se a cadeia de interceptor atual está vazia ou o índice de coordenadas do interceptor que está vindo é igual ao último na cadeia de interceptor, então o método alvo é executado diretamente e, em seguida, a cadeia de interceptor é obtida de acordo com currentInterceptorIndex O interceptor correspondente (obtive o ExposeInvocationInterceptor pela primeira vez). Em seguida, olhamos para a seguinte chave ((MethodInterceptor) interceptorOrInterceptionAdvice) .invoke (this) esta linha de código, observe que o objeto ReflectiveMethodInvocation atual é passado aqui, e então vamos dar uma olhada

Aqui chamamos o método proced com o objeto ReflectiveMethodInvocation passado novamente, ou seja, neste momento estamos de volta ao método proced, e agora obtemos o segundo interceptor da cadeia de interceptores, então isso é equivalente a uma camada um Para chamar o método invoke do próximo interceptor camada por camada, veremos diretamente o último interceptor MethodBeforeAdviceInterceptor

 Podemos ver que antes que o método proceda seja executado, existe um método before.Na verdade, este método é usado para executar a pré-notificação, e então iremos executar o procedimento após a pré-notificação ser executada.

Neste ponto, a condição de julgamento no início do método de procedimento pode determinar que o interceptor atual é o último interceptor na cadeia de interceptores, então o método alvo é executado diretamente, para que possamos ver que o log atende ao resultado da pré-notificação

 Então, como o método invoke do nosso interceptor é chamado camada por camada, quando o último interceptor executou o método invoke, ele continua a retornar ao método invoke do penúltimo interceptor. Aqui podemos passar uma imagem Para desenhar o fluxo de chamada do método invoke

 6. Resumo do processo de AOP

Em primeiro lugar, a anotação @EnableAspectJAutoProxy no início ativa a função AOP. O objetivo é importar o componente AnnotationAwareAspectJAutoProxyCreator para o contêiner, e esse componente é um BeanPostProcessor. Durante a inicialização do contêiner Spring, há um método registerBeanPostProcessors no método de atualização do Spring. Este método é Crie todos os BeanPostProcessors, de forma que o componente AnnotationAwareAspectJAutoProxyCreator seja criado aqui e, em seguida, vá para o método finishBeanFactoryInitialization para criar o Bean de instância única restante, neste momento os componentes de lógica de negócios em nosso programa, incluindo nossos componentes de aspecto, serão criados e Antes e depois de esses componentes serem criados, o BeanPostProcessor que foi criado no contêiner será interceptado e processado. Entre eles, nosso componente AnnotationAwareAspectJAutoProxyCreator tentará retornar um Bean antes de criar o Bean. Se não puder retornar, ele executará normalmente para criar o Bean. Depois de criar o Bean, AnnotationAwareAspectJAutoProxyCreator usará o método postProcessAfterInitialization (chamado após o Bean ser criado) para determinar se o Bean precisa criar um objeto proxy. Aqui, você pode usar o proxy dinâmico JDK ou o proxy dinâmico cglib de acordo com se a classe implementa a interface. Se ele precisar ser aprimorado, isto é, para criar um objeto proxy, envolva o pointcut e todos os métodos de notificação do pointcut em um intensificador de orientador e, a seguir, crie um objeto proxy. Ao executar o método de destino, primeiro obtenha a cadeia de interceptor do método de destino e use o mecanismo de chamada de cadeia do interceptor para inserir cada interceptor de cada vez para executar o método de aprimoramento.

 

Acho que você gosta

Origin blog.csdn.net/weixin_37689658/article/details/101173206
Recomendado
Clasificación