Processus d'implémentation Spring AOP et analyse du code source

Préface

L'interprétation littérale de l'AOP est la programmation orientée aspect. La programmation orientée aspect est un modèle de programmation. Nous savons que JAVA est orienté objet, ce qui est la POO. La programmation orientée objet de la POO convient pour définir des relations verticales, mais c'est ne convient pas pour définir une relation horizontale. Donc, pour faire face à ces inconvénients de l'existence de cette POO, le modèle de programmation orienté aspect AOP est utilisé comme un complément à orienté objet, qui est utilisé pour extraire et encapsuler les comportements et la logique communs qui ne sont pas liés à l'entreprise mais En tant que module réutilisable, ce module est nommé "Aspect", ce qui réduit le code répétitif dans le système, réduit le couplage entre les modules et améliore la maintenabilité du système. Il peut être utilisé pour l'authentification d'autorité, le journal et le traitement des transactions.

Présentation du proxy AOP

Voici l'implémentation d'AOP. Notez qu'il ne s'agit pas de Spring AOP. Tout d'abord, la clé de l'implémentation d'AOP réside dans le mode proxy. Le proxy AOP est divisé en proxy dynamique et proxy statique. Comme nous le savons, Spring AOP appartient à dynamic proxy, et le représentant du proxy statique est AspectJ;

Proxy statique

AspectJ est une amélioration du proxy statique. Le proxy dit statique signifie que le framework AOP générera des classes proxy AOP pendant la phase de compilation, il s'agit donc également d'une amélioration au moment de la compilation. Le proxy statique entrera AspectJ (aspects) dans le bytecode java pendant la phase de compilation., Lorsqu'il s'exécute, il s'agit de l'objet AOP amélioré;

Proxy dynamique

SpringAOP est un proxy dynamique. Le proxy dit dynamique signifie que le framework AOP ne modifie pas le fichier bytecode, mais génère un objet AOP pour la méthode à un instant zéro dans la mémoire à chaque exécution. Cet objet AOP contient toutes les méthodes de l'objet cible. Et un traitement amélioré dans des aspects spécifiques et des méthodes de rappel de l'objet d'origine;

la différence

La différence entre le proxy statique et le proxy dynamique est que le moment de génération des objets proxy AOP est différent. Par rapport à la méthode de proxy statique d'AspectJ, elle offre de meilleures performances, mais AspectJ nécessite un compilateur spécifique pour le traitement, tandis que SpringAOP ne nécessite pas de compilateur spécifique pour traiter.

Proxy dynamique SpringAOP

On sait déjà que SpringAOP est implémenté par proxy dynamique.Dans le proxy dynamique, il existe deux méthodes d'implémentation: le proxy dynamique JDK et le proxy dynamique CGLIB! Si la classe proxy n'implémente pas l'interface InvocationHandler dans le proxy dynamique JDK, SpringAOP choisira d'utiliser CGLIB pour proxy dynamiquement la classe cible! Par défaut @EnableAspectJAutoProxy ne spécifie pas proxyTargetClass = true (la valeur par défaut n'est pas écrite comme false), et notre classe métier implémente l'interface d'interface InvocationHandler, alors AOP utilisera le proxy dynamique JDK, s'il n'implémente pas l'interface InvocationHandler, utilisez le Proxy CGLIB, si @EnableAspectJAutoProxy a Specify proxyTargetClass = true, alors il est obligatoire d'utiliser CGLIB, que la classe métier implémente ou non l'interface InvocationHandler, ainsi que l'amélioration de la référence (la méthode B est appelée dans la méthode A) si exposeProxy = true est spécifié dans l'annotation @EnableAspectJAutoProxy (la valeur par défaut est false), Ensuite, l'objet proxy sera exposé à la variable de thread, donc lorsque vous appelez, retirez l'objet proxy de la variable de thread et appelez-le via l'objet proxy, puis le Une méthode est améliorée et la méthode B est également améliorée! Similaire à la méthode de transaction A appelle la méthode de transaction B

  • Le proxy dynamique JDK ne fournit que le proxy d'interface et ne prend pas en charge le proxy de classe. Le noyau est la classe Proxy. InvocationHandle appelle le code de la classe cible via la réflexion de la méthode invoke (), en associant dynamiquement la logique transversale et l'activité, puis Proxy utilise InvocationHandle crée dynamiquement une instance conforme à une certaine interface pour générer un objet proxy de la classe cible

  • CGLIB (Code Generation Library) est une bibliothèque de classes pour la génération de code, qui peut générer dynamiquement un objet de sous-classe d'une classe spécifiée au moment de l'exécution, remplacer des méthodes spécifiques et ajouter du code amélioré pour atteindre l'AOP. CGLIB est un proxy dynamique de manière intégrée, donc si une classe est marquée comme finale, alors CGLIB ne peut pas être utilisé comme proxy dynamique.
    InvocationHandler

Terminologie AOP

Joinpoint

Est une méthode qui doit être améliorée

PointCut

Un ensemble de points de connexion est appelé un point tangent

Aspect

C'est une classe composée de points de coupure, de points de connexion et de notifications.

Conseils

  • Pré-notification (avant): effectuez certaines opérations avant d'exécuter le code métier, comme l'obtention de l'objet de connexion
  • Après notification (après): faites quelque chose après l'exécution du code métier, il sera exécuté indépendamment du fait qu'une exception se produise, comme la fermeture de l'objet de connexion
  • Notification d'exception (afterThrowing): opération qui doit être effectuée lorsqu'une exception se produit après l'exécution du code métier, telle que l'annulation de la transaction
  • Notification de retour (afterReturning), l'opération qui sera effectuée sans exception après l'exécution du code métier
  • Autour de la notification (autour), il n'y a pas d'opération correspondante pour la transaction dont nous parlons actuellement, donc je n'en parlerai pas pour le moment

Cibler
les objets métier à renforcer

Tissage

Le tissage est le processus d'ajout d'améliorations à des points de connexion spécifiques à la classe cible. Le tissage est un terme vivant, plus précisément le processus de génération d'objets proxy et d'intégration du contenu des aspects dans les processus métier.

Procuration

Une fois qu'une classe est tissée et améliorée par AOP, une classe proxy est créée.

Exemple de code SpringAOP

cible

@Service
public class A {
    
    
    public void f(){
    
    
        System.out.println("我被执行了");
    }
}

section

@Component
@Aspect
public class MyAspect {
    
    
	
	//切点
    @Pointcut("execution(* com.xxx.xxx..*(..))")
    private void anyOldTransfcr(){
    
    }
	//com.xxx.xxx..*(..))这个中描述的每个方法为织入点

	//通知
    @Before("anyOldTransfcr()")
    public void advice(JoinPoint joinPoint){
    
    
        //String methodName=joinPoint.getSignature().getName();
        //System.out.println("执行的方法--->"+methodName);
        //System.out.println(Arrays.asList(joinPoint.getArgs()));
        System.out.println("--------开始执行-------");
    }

	//通知
    @After("anyOldTransfcr()")
    public void advice2(){
    
    
        System.out.println("--------结束执行-------");
    }

}

Classe de départ principale

@EnableAspectJAutoProxy(proxyTargetClass = true)

补充:这里在切面中有个@Aspect这个注解,和上面提到的AspectJ静态代理其实是有点关系的,因为Spring在刚开始实现AOP的时候写的语法是不太友好的,然后Spring后面在迭代的过程中实现AOP就参照了AspectJ的语法,注意是语法!

Exécuter les résultats après le démarrage
Insérez la description de l'image ici

Analyse du processus d'implémentation du code source SpringAOP

Ici, vous devez parcourir tout le processus de SpringIOC.Pour le dire franchement, SpringAOP est une fonction implémentée par une certaine partie d'IOC! Pour le processus SpringIOC, veuillez consulter Analyse du code source Spring (processus de peignage). Dans cet article, il y a l'image suivante.
Insérez la description de l'image ici
Le processus de création d'objets proxy AOP peut être vu dans l'image ci-dessus. On peut voir qu'il est implémenté dans le processus de création de Bean Le processus AOP est divisé comme suit;

  1. Recherche de facette
  2. Notification d'aspect du cache
  3. Déterminez si le bean actuel appartient au point de tissage via l'expression de coupe de point
  4. Est le point de tissage pour créer un objet proxy
  5. Méthode cible d'exécution

1. Recherche par section

Chaque fois qu'un Bean est créé, il entrera la méthode createBean dans la classe AbstractAutowireCapableBeanFactory Il y a un code très clé sur AOP dans cette méthode;
Insérez la description de l'image ici

		try {
    
    
			// 给BeanPostProcessors一个返回代理而不是目标bean实例的机会
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
    
    
				return bean;
			}
		}

Après avoir entré cette ligne de code,
Insérez la description de l'image ici
continuer à entrer
Insérez la description de l'image ici
ici est particulièrement important, lorsque nous activons l'annotation de fonction AOP, @EnableAspectJAutoProxy (proxyTargetClass = true)

Cette annotation nous aidera à importer une classe AspectJAutoProxyRegistrar.
Insérez la description de l'image ici
Entrez la classe AspectJAutoProxyRegistrar. Cette classe implémente l'interface ImportBeanDefinitionRegistrar et réécrit les registerBeanDefinitions. Voici donc certainement pour nous aider à enregistrer le Bean, et entrez cette méthode pour
Insérez la description de l'image ici
Insérez la description de l'image ici
enregistrer un AnnotationAwareCpectJorxyProxy. Oui, ce haricot est très important!

Retour à notre code de processus AOP

Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);

Cette ligne de code entre le postProcessBeforeInstantiation dans la classe AbstractAutoProxyCreator lorsque ibp est la méthode AnnotationAwareAspectJAutoProxyCreator injectée ci-dessus, car le niveau supérieur de AnnotationAwareAspectJAutoProxyCreator hérite de la méthode AbstractAutoProxyCreator.
Insérez la description de l'image ici
Cette méthode shouldSkip (beanClass, beanName) appellera la méthode shouldSkip dans la classe AspectJAwareAdvisorAutoProxyCreator. L'
Insérez la description de l'image ici
Insérez la description de l'image ici
appel ici ira à buildAspectJAdvisors dans la classe BeanFactoryAspectJAdvisorsBuilder. Cette méthode consiste à rechercher la classe d'aspect, puis à renvoyer le type de notification défini dans la classe d'aspect .

2. Notification d'aspect du cache

List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

Dans cette ligne de code, une collection d'objets de type notification est générée, et la classe d'aspect est utilisée comme clé, et la collection d'objets de notification est stockée en tant que valeur de la classe d'aspect actuelle en tant que clé!
Insérez la description de l'image ici
Dans cette étape, le processus d'obtention de la classe d'aspect et de génération de l'objet de notification en fonction de la notification dans la classe d'aspect prend du temps, de sorte que l'objet de notification analysé est ajouté au cache. Lorsque la création ultérieure du Bean arrive ici, il déterminera d'abord si aspectBeanNames est vide. S'il est vide, récupérez simplement les données dans le cache et retournez

Selon le type de notification dans la classe d'aspect, la
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); ligne de code qui génère l'objet de notification est utilisée comme entrée, et entre enfin la méthode getAdvice dans la classe ReflectiveAspectJAdvisorFactory
Insérez la description de l'image ici

De retour au processus principal, le processus principal a trouvé la classe d'aspect et l'objet de notification a été mis en cache ici, puis démarrez la méthode d'origine et revenez au
Insérez la description de l'image ici
processus principal et commencez à entrer dans le processus de création de Bean;
Insérez la description de l'image ici
nous sautons le processus de attribution d'attribut. look, et AOP n'a pas beaucoup d'importance, directement dans le processus d'initialisation de Bean
Insérez la description de l'image ici
après l'initialisation sera effectuée
Insérez la description de l'image ici
Insérez la description de l'image ici
ici, il y a une clé, ouverte ici après @EnableAspectJAutoProxy commentaire AOP mentionné ci-dessus BeanPostProcessor sera plus un AnnotationAwareAspectJAutoProxyCreator
Insérez la description de l'image ici
lorsque le processeur ici Lorsqu'il s'agit de l'objet AnnotationAwareAspectJAutoProxyCreator, entrez la méthode postProcessAfterInitialization dans la classe AbstractAutoProxyCreator.
Insérez la description de l'image ici
Insérez la description de l'image ici
Cette ligne de code ira à 1. Trouvez la classe d'aspect, 2. Mettez en cache l'objet de notification dans la classe d'aspect, mais ne faites que cette opération, mais la première fois que la méthode shouldSkip est appelée, c'est déjà Après avoir terminé les deux opérations de 1. Trouvez la classe d'aspect et 2. Mettez en cache l'objet de notification dans la classe d'aspect, alors la logique ne sera pas exécutée à nouveau ici, mais après avoir entré le buildAspectJAdvisors () , il reviendra directement à la première exécution de buildAspectJAdvisors () L'ensemble de résultats de l'objet de notification mis en cache par la méthode!

3. Déterminez si le bean actuel appartient au point de tissage via l'expression de coupe de point.

Insérez la description de l'image ici
Si la valeur renvoyée est nulle, cela signifie que le bean qui doit être initialisé n'a pas besoin de créer un objet proxy. Si le retour n'est pas nul, commencez à créer un objet proxy.

4. Est le point de tissage pour créer un objet proxy

Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici
Utiliser CGLIB pour générer des objets proxy L'Insérez la description de l'image ici
introduction de Spring AOP au début de l'article explique pourquoi CGLIB est utilisé pour compléter le proxy dynamique!

5. Application de la méthode cible

Insérez la description de l'image ici
Lorsque la méthode f est appelée, c'est la méthode f qui entre dans l'objet proxy.
Insérez la description de l'image ici
Comme le CGLIB est utilisé pour terminer le proxy dynamique, l'exécution est également effectuée par l'exécuteur d'objet proxy pris en charge. Le CGLIB est effectué par CglibAopProxy et le JDK est exécuté par le JdkDynamicAopProxy! En fait, il est finalement exécuté via la méthode procède () dans la classe ReflectiveMethodInvocation!
Insérez la description de l'image ici

//当前拦截器的的索引
this.currentInterceptorIndex

//拦截器集合
this.interceptorsAndDynamicMethodMatchers

//当拦截器索引等于拦截器集合数组长度-1时,执行目标方法
this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1

//执行目标方法
return invokeJoinpoint();

//完成当前拦截器获取和当前拦截器索引++操作
Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

//使用当前索引获取到的拦截器执行invoke方法逻辑
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

这里在invoke方法中传入的是this就是为了递归循环调用proceed()方法自己

Insérez la description de l'image ici
Chaque récursivité ajoute en fait un bloc de code logique au bloc de code, puis l'exécute. Le code squelette récursif complet est comme ci-dessus. Exécutez de haut en bas!

  1. AOP Aronud avant…
  2. AOP avant avis…
  3. La méthode cible est exécutée ...
  4. AOP Aronud après…
  5. AOP après avis…
  6. AOP AfterReturning Advice: (Si l'exécution normale est terminée, exécutez la méthode actuelle)
  7. AOP AfterThrowing Advice ... (Si une exception est levée, la méthode actuelle est exécutée)

Ce flux d'appels est complété par la chaîne de responsabilité + récursivité

Je suppose que tu aimes

Origine blog.csdn.net/CSDN877425287/article/details/114328007
conseillé
Classement