Annuaire d'articles
avant-propos
Dans le développement logiciel actuel, la programmation orientée objet (POO) est devenue le paradigme de programmation dominant. Elle utilise les objets comme composants de base des programmes et organise le code à travers des fonctionnalités telles que l'encapsulation, l'héritage et le polymorphisme. . Cependant, avec l'expansion continue de l'échelle et de la complexité des logiciels, la POO peut être confrontée à certains défis dans certains cas.
Un problème courant est le couplage entre la logique métier et横切关注点(cross-cutting concerns)
. Ce qu'on appelle 横切关注点就是那些在应用程序中分布广泛,与核心业务逻辑代码相互交织在一起的功能
, comme le jugement de connexion, la journalisation, la gestion des transactions, le contrôle d'autorité, etc. Le fait de coupler étroitement ces préoccupations avec la logique métier de base conduit à un code dupliqué et difficile à maintenir . Par conséquent, dans ce cas, un paradigme de programmation de programmation orientée aspect (Aspect-Oriented Programming, appelé AOP) a vu le jour.
1. Apprendre à connaître Spring AOP pour la première fois
Dans la programmation orientée objet traditionnelle, nous organisons le code par encapsulation, héritage et polymorphisme, et encapsulons la logique fonctionnelle associée dans des méthodes objet. Cependant, dans le développement réel, en plus de la logique métier de base, il existe souvent des fonctions non pertinentes mais nécessaires, telles que la journalisation, la surveillance des performances, le contrôle de sécurité, etc. Ces fonctions sont souvent dispersées à plusieurs endroits du code, ce qui donne lieu à un code répétitif et difficile à maintenir.
1.1 Qu'est-ce que l'AOP
La programmation orientée aspect (AOP) est un paradigme de programmation créé pour résoudre ce problème de répétition de code et de difficulté de maintenance. AOP 的核心思想是将横切关注点(cross-cutting concerns)从主要的业务逻辑中分离出来,以模块化的方式进行管理
. Les préoccupations transversales concernent les fonctions largement réparties dans l'application et étroitement liées à la logique métier de base, telles que la journalisation, les transactions, les autorisations, etc.
AOP divise le système en deux parties principales : 核心关注点和横切关注点
. Les préoccupations essentielles constituent la principale logique métier de l'application, tandis que les préoccupations transversales sont des fonctions qui ne sont pas liées aux préoccupations essentielles mais qui sont nécessaires .
AOP résume les préoccupations transversales en modules appelés aspects (Aspect), puis les gère et les maintient indépendamment de la logique métier principale . De cette manière, nous pouvons ajouter, modifier ou supprimer diverses fonctions de manière flexible sans modifier la logique métier principale, améliorant ainsi la maintenabilité et l'évolutivité du code.
1.2 Qu'est-ce que Spring AOP
Tout comme la relation entre IoC et DI, AOP是一种思想,而 Spring AOP 则是 AOP 思想的一种实现
. Dans le même temps, Spring AOP est également un module important du framework Spring, qui permet aux développeurs d'implémenter facilement une programmation orientée aspect.
En bref, Spring AOP s'appuie sur les concepts AOP traditionnels pour fournir un moyen plus simple et plus pratique de gérer les préoccupations transversales. Il met en œuvre la modularisation des préoccupations transversales en exécutant la logique de l'aspect avant, après ou autour des préoccupations principales grâce à la technologie proxy. Par rapport à la programmation orientée objet traditionnelle, l'utilisation de Spring AOP permet de mieux séparer les problèmes, rendant le code plus clair et plus maintenable.
Spring AOP prend en charge deux types de proxy : 基于接口的 JDK 动态代理
et 基于类的 CGLIB 动态代理
. Il fournit également une série d'annotations et d'options de configuration, permettant aux développeurs de définir de manière flexible des aspects et des conseils (Conseils) et de les appliquer à différents objets cibles.
2. Le concept de base de l'AOP
Dans la programmation orientée aspects (AOP), plusieurs concepts fondamentaux sont essentiels pour nous aider à comprendre comment gérer et appliquer des préoccupations transversales. Ces concepts incluent des aspects, des points de coupe, des conseils et des points de jointure, qui forment ensemble la base de l'AOP.
2.1 Aspects
切面(Aspect)由切点(Pointcut)和通知(Advice)组成,它是对横切关注点的抽象化
. Il définit quel type de logique transversale doit être exécuté et à quels points de coupe. Un aspect est une unité modulaire qui sépare les préoccupations transversales communes de l'activité principale pour une meilleure gestion et maintenance.
De manière plus générale, un aspect équivaut à une classe en Java, qui représente le contenu spécifique d'un certain aspect, semblable à un module de code.
- Par exemple, nous pouvons considérer le jugement de connexion de l'utilisateur comme un « aspect » qui contient la logique qui doit être exécutée pendant le processus de connexion de l'utilisateur. De même, l'enregistrement statistique du journal est également une « section » qui comprend les opérations associées qui doivent être enregistrées lors de l'exécution du code.
- Un aspect est comme une boîte à outils avec des fonctions spécifiques, et chaque boîte à outils contient un ensemble d'opérations associées. Dans le code, un aspect définit où (points de coupe) et comment effectuer ces opérations. Lorsque nous devons appliquer des fonctions similaires à différents endroits, nous pouvons créer un aspect pour y encapsuler les opérations associées.
2.2 Point de coupe
切点(Pointcut)可以被理解为匹配连接点(Join Point)的谓词,或者说它是一组规则的集合,用于选择在哪些连接点上应用横切逻辑
. Les pointcuts AspectJ pointcut expression language
décrivent ces règles à l'aide de , un langage qui vous permet de définir de manière flexible des conditions de correspondance pour sélectionner avec précision des points de jointure spécifiques.
AspectJ pointcut expression language
Est un langage d'expression utilisé pour définir des pointscuts (Pointcut), qui est un élément clé du framework AspectJ. Ce langage d'expression nous permet de décrire de manière flexible à quels points de jonction les conseils doivent être appliqués.
Le rôle du pointcut est de nous fournir un moyen de définir des règles afin de filtrer les points de connexion qui remplissent les conditions. Lorsque les points de connexion répondent aux règles définies par le pointcut, on peut appliquer des conseils (Advice) à ces points de connexion, de manière à insérer une logique transversale à ces positions spécifiques. Cela nous permet d'insérer de manière sélective des comportements spécifiques dans le code sans coupler les préoccupations transversales avec la logique métier principale.
2.3 Conseils
En AOP, un aspect n’est pas seulement un concept abstrait, il a un objectif clair. Les aspects doivent accomplir des tâches spécifiques, et dans la terminologie AOP, ces tâches sont appelées conseils (Advice) . 通知定义了切面的具体行为:它解决了切面是什么、何时使用以及在何时执行这些行为的问题
.
Dans la classe aspect de Spring, différentes annotations peuvent être utilisées pour marquer les méthodes comme méthodes de notification , qui seront appelées lorsque les conditions seront remplies :
-
Utilisation de la pré-notification
@Before
: la méthode de notification sera exécutée avant l'appel de la méthode cible, et certaines opérations de prétraitement pourront être effectuées. -
Utilisation de la post-notification
@After
: la méthode de notification sera appelée après que la méthode cible ait renvoyé ou lancé une exception, et certaines opérations consécutives peuvent être effectuées. -
Utilisation de la notification après le retour
@AfterReturning
: la méthode de notification sera appelée après le retour réussi de la méthode cible et la valeur de retour pourra être traitée. -
Utilisation de la notification après le lancement d'une exception
@AfterThrowing
: la méthode de notification sera appelée après que la méthode cible ait levé une exception, qui peut gérer l'exception. -
Utilisation de la notification Surround
@Around
: la notification encapsule la méthode notifiée, exécute un comportement personnalisé avant et après l'appel de la méthode cible et peut également contrôler s'il faut appeler la méthode cible et comment gérer la valeur de retour.
2.4 Joindre des points
Un point de jointure représente un point réel dans l'exécution du programme et inclut tous les points pouvant déclencher un pointcut . En d’autres termes, le point de jointure est l’occurrence réelle dans le code du pointcut. Des conseils (Advice) seront exécutés sur le point de connexion, de manière à réaliser l'ajout ou la modification de préoccupations transversales. Un point de jointure est un point dans AOP qui est intercepté.
Le concept de l'ensemble du composant AOP est illustré dans la figure ci-dessous, en prenant comme exemple plusieurs pages pour accéder aux autorisations de connexion des utilisateurs :
En plus des aspects, des points de coupe, des conseils et des points de jointure, AOP couvre d'autres concepts et termes importants. Voici quelques concepts connexes :
-
Introduction : Une introduction est un type spécial de notification qui permet d'ajouter une nouvelle méthode ou un nouveau champ à une classe existante. On parvient ainsi à introduire de nouvelles fonctionnalités dans des classes existantes sans modifier leur code.
-
Objet cible (Target Object) : L'objet cible est l'objet de l'application, qui est affecté et intercepté par l'aspect. Les aspects appliquent des conseils sur les points de jointure sur les objets cibles.
-
Proxy (Proxy) : Le proxy est le packaging de l'objet cible. Il permet à l'aspect d'insérer des conseils au point de connexion de l'objet cible pour mettre en œuvre une logique transversale. Les proxys peuvent être implémentés via des proxys statiques, des proxys dynamiques JDK ou des proxys dynamiques CGLIB.
-
Tissage : Le tissage est le processus de connexion d’aspects avec des objets cibles. Au moment de la compilation, du chargement ou de l'exécution, des conseils d'aspect sont insérés dans le point de jointure de l'objet cible pour mettre en œuvre la logique des préoccupations transversales.
-
Ordre des conseils : s'il y a plusieurs conseils sur un pointcut, l'ordre dans lequel les conseils sont exécutés peut être important. L'ordre des conseils définit l'ordre dans lequel plusieurs conseils sont exécutés sur les points de coupe.
-
Priorité des aspects : s'il y a plusieurs aspects dans la candidature, la priorité des aspects peut affecter l'ordre d'exécution de l'avis. La priorité de l'aspect détermine l'ordre d'exécution parmi plusieurs aspects.
-
Aspects dynamiques (Aspects dynamiques) : L'aspect dynamique est un mécanisme permettant de déterminer s'il convient d'appliquer un aspect en fonction de certaines conditions au moment de l'exécution. Vous permet de choisir dynamiquement d'appliquer ou non des facettes à l'objet cible selon vos besoins.
3. Utilisation de Spring AOP
Les concepts ci - dessus peuvent être considérés comme obscurs et difficiles à comprendre.Ce qui suit utilise Spring AOP pour simuler et réaliser les fonctions d'AOP, ce qui peut nous aider à mieux comprendre AOP. À ce stade, notre objectif est d'intercepter UserController
toutes les méthodes de , et chaque fois qu'une des méthodes est appelée, l'événement de notification correspondant sera exécuté.
Les étapes pour utiliser Spring AOP sont les suivantes :
- Ajouter la prise en charge du framework Spring AOP ;
- Définir les facettes et les points ;
- Définissez les méthodes de notification associées.
3.1 Ajouter la prise en charge du framework Spring AOP
pom.xml
Ajoutez la configuration suivante dans :
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.7.14</version>
</dependency>
3.2 Définir les facettes et les points
L'aspect représente le contenu spécifique d'un certain aspect, tel que le jugement de l'autorité de connexion de l'utilisateur, et l'aspect ici est le UserController
traitement de la classe. L’une d’elles consiste à définir des règles d’interception spécifiques. Par exemple le code suivant :
@Aspect // 表示定义一个切面(类)
@Component
public class UserAspect {
// 创建切点(方法)定义拦截规则
@Pointcut("execution(public * com.example.demo.controller.UserController.*(..))")
public void pointcut() {
}
}
Dans ce code, une classe d'aspect est créée UserAspect
et @Aspect
annotée pour la marquer comme aspect. En même temps, utilisez @Component
des annotations pour déclarer cet aspect comme composant géré par Spring afin que le conteneur Spring puisse le gérer et le reconnaître.
Dans UserAspect
la classe, @Pointcut
une annotation est utilisée pour définir un pointcut, et la règle d'interception du pointcut est de correspondre à UserController
toutes les méthodes publiques de la classe (public * com.example.demo.controller.UserController.*(..))
. Cela signifie que notre pointcut se UserController
déclenchera sur toutes les méthodes publiques de la classe.
Il convient de noter que pointcut
le corps de la méthode peut être vide, car @Pointcut
l'annotation n'est utilisée que pour définir l'expression de pointcut et le code logique réel sera implémenté dans la méthode de conseil.
Description de l'expression Pointcut :
les expressions Pointcut sont utilisées pour définir des règles de correspondance pour les pointscuts, qui déterminent les points de jointure sur lesquels appliquer les conseils. AspectJ prend en charge trois types de caractères génériques pour créer des expressions pointcut :
*
: correspond à n'importe quel caractère, à un seul élément (package, classe ou méthode, paramètre de méthode)...
: Correspond à n'importe quel caractère et peut correspondre à plusieurs éléments. Lors de la représentation d'une classe, elle doit*
être utilisée conjointement avec , par exemple :com.cad..*
pour représentercom.cad
toutes les classes de tous les packages descendants sous le package.+
: Indique qu'il faut faire correspondre toutes les classes de la classe spécifiée par type. Il doit être suivi du nom de la classe, ce quicom.cad.Car+
signifie que toutes les sous-classes héritant de cette classe s'incluent.Les expressions pointcut utilisent généralement
execution()
des fonctions pointcut, qui sont les fonctions pointcut les plus couramment utilisées pour les méthodes de correspondance.
Exemples d'expressions de point de coupe :
voici quelques exemples d'expressions de point de coupe pour mieux comprendre comment créer des règles de point de coupe :
execution(* com.cad.demo.User.*(..))
: correspond àUser
toutes les méthodes de la classe.execution(* com.cad.demo.User+.*(..))
: correspond àUser
toutes les méthodes des sous-classes de la classe, y compris elle-même.execution(* com.cad.*.*(..))
: Faites correspondrecom.cad
toutes les méthodes de toutes les classes du package.execution(* com.cad..*.*(..))
: correspond àcom.cad
toutes les méthodes de toutes les classes du package et à tous ses packages descendants.execution(* addUser(String, int))
:addUser
Méthode de correspondance, et le premier type de paramètre estString
et le deuxième type de paramètre estint
.
3.3 Définir les méthodes de notification associées
La notification définit l'activité spécifique à effectuer par la méthode interceptée. Par exemple, la méthode de vérification de l'autorité de connexion de l'utilisateur est l'activité spécifique à effectuer, mais cette fois il ne s'agit que d'une simple opération d'impression. Dans Spring AOP, les annotations suivantes peuvent être utilisées sur la méthode, qui définiront la méthode comme méthode de notification et avertiront la méthode à appeler une fois la condition remplie :
-
Utilisation de la pré-notification
@Before
: la méthode de notification sera exécutée avant l'appel de la méthode cible, et certaines opérations de prétraitement pourront être effectuées. -
Utilisation de la post-notification
@After
: la méthode de notification sera appelée après que la méthode cible ait renvoyé ou lancé une exception, et certaines opérations consécutives peuvent être effectuées. -
Utilisation de la notification après le retour
@AfterReturning
: la méthode de notification sera appelée après le retour réussi de la méthode cible et la valeur de retour pourra être traitée. -
Utilisation de la notification après le lancement d'une exception
@AfterThrowing
: la méthode de notification sera appelée après que la méthode cible ait levé une exception, qui peut gérer l'exception. -
Utilisation de la notification Surround
@Around
: la notification encapsule la méthode notifiée, exécute un comportement personnalisé avant et après l'appel de la méthode cible et peut également contrôler s'il faut appeler la méthode cible et comment gérer la valeur de retour.
Le code de notification implémenté ici est le suivant :
// 创建一个切面(类)
@Aspect
@Component
public class UserAscept {
// 创建切点(方法)定义拦截规则
@Pointcut("execution(public * com.example.demo.controller.UserController.*(..))")
public void pointcut() {
}
// 前置通知
@Before("pointcut()")
public void doBefore() {
System.out.println("执行了前置通知:" + LocalDateTime.now());
}
// 后置通知
@After("pointcut()")
public void doAfter() {
System.out.println("执行了后置通知:" + LocalDateTime.now());
}
// 返回后通知
@AfterReturning("pointcut()")
public void doAfterReturning() {
System.out.println("执行了返回后通知:" + LocalDateTime.now());
}
// 抛异常后通知
@AfterThrowing("pointcut()")
public void doAfterThrowing() {
System.out.println("抛异常后通知:" + LocalDateTime.now());
}
// 环绕通知
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) {
Object proceed = null;
System.out.println("Around 方法开始执行:" + LocalDateTime.now());
try {
// 执行拦截的方法
proceed = joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("Around 方法结束执行: " + LocalDateTime.now());
return proceed;
}
}
Dans ce code , différents types de méthodes de notification sont définis et chaque méthode est marquée des annotations correspondantes, telles que @Before
, , et . Ces annotations associent les méthodes de conseil aux points de coupe ( points de coupe définis à l'aide de la méthode). Lorsque la méthode in est appelée, elle sera interceptée par le pointcut, puis ces méthodes de notification correspondantes seront exécutées.@After
@AfterReturning
@AfterThrowing
@Around
pointcut()
UserController
Une note sur la méthode de bouclage ci-dessus :
Parmi eux, les conseils environnants sont le type de conseil le plus spécial et le plus flexible de Spring AOP. Il permet aux développeurs de contrôler totalement les appels de méthode interceptés, y compris la possibilité d'insérer une logique personnalisée avant et après l'exécution de la méthode cible et lorsque des exceptions sont interceptées. Cette fonctionnalité rend les conseils surround très puissants pour les scénarios où un contrôle total sur la logique transversale est requis.
Le code ci-dessus montre comment implémenter les notifications surround. Les notifications environnantes sont marquées d' @Around
annotations et le paramètre de la méthode de notification est un ProceedingJoinPoint
objet, ce qui nous permet d'appeler la méthode à un moment approprié proceed()
pour exécuter la méthode interceptée.
Dans cette méthode de notification surround :
-
Le paramètre de la méthode
joinPoint
est unProceedingJoinPoint
objet, qui représente le point d'appel de la méthode cible, etproceed()
la méthode peut être appelée pour exécuter la méthode interceptée en cas de besoin. -
Vous pouvez
proceed()
insérer une logique personnalisée avant et après l’appel de méthode pour obtenir un comportement transversal spécifique. -
L'exception qui peut être levée peut être interceptée et la situation d'exception peut être gérée.
-
La valeur de retour vous permet de contrôler la valeur de retour de la méthode cible ou d'effectuer une gestion appropriée de la valeur de retour.
Quatrièmement, le principe de mise en œuvre de Spring AOP
4.1 Proxy dynamique
Spring AOP est basé sur des proxys dynamiques, sa prise en charge est donc limitée à l'interception au niveau de la méthode. Cela signifie que Spring AOP est principalement utilisé pour intercepter et gérer les appels de méthodes et ne peut pas intercepter directement les opérations au niveau de la classe.
Dans Spring AOP, il existe deux manières d'implémenter un proxy dynamique : JDK Proxy et CGLIB. Par défaut, Spring AOP choisira la méthode proxy à utiliser selon que la classe cible implémente ou non l'interface :
-
Proxy JDK : si la classe cible implémente l'interface, Spring AOP utilisera le proxy JDK pour générer la classe proxy.
java.lang.reflect.Proxy
JDK Proxy est implémenté sur la base des classes de la bibliothèque standard Java , exigeant que la classe cible implémente au moins une interface. -
CGLIB : si la classe cible n'implémente pas l'interface, Spring AOP utilisera CGLIB pour générer la classe proxy. CGLIB est une puissante bibliothèque tierce capable de créer dynamiquement des sous-classes de classes au moment de l'exécution pour implémenter des proxys.
Cela signifie que lors de l'utilisation de Spring AOP, si la classe cible implémente l'interface, Spring utilisera le proxy JDK pour créer le proxy. Si la classe cible n'implémente pas l'interface, Spring utilisera CGLIB pour créer le proxy. Dans certains cas, vous devrez peut-être prêter attention à certains effets subtils que le proxy CGLIB peut apporter, comme le fait que la méthode finale ne peut pas être interceptée, etc.
4.2 Proxy dynamique JDK
JDK Proxy est un mécanisme de proxy dynamique dans la bibliothèque standard Java. Il crée des objets proxy basés sur les interfaces implémentées par la classe cible pour insérer une logique transversale avant et après les appels de méthode. JDK Proxy est principalement utilisé pour intercepter les appels de méthode des classes qui implémentent des interfaces.
Implémentation du proxy JDK :
- Tout d’abord,
InvocationHandler
créez un gestionnaire d’appel de méthode en implémentant l’interface. Ce gestionnaire définit la logique à exécuter lors de l'interception des appels de méthode. - Ensuite, utilisez
Proxy
la classe pour créer l'objet proxy.Proxy
La méthode de la classenewProxyInstance()
accepte unClassLoader
, un tableau d'interface et unInvocationHandler
objet comme paramètres, puis génère dynamiquement le bytecode de la classe proxy pour créer une instance de proxy.
Limites du proxy JDK :
- JDK Proxy nécessite que la classe cible implémente au moins une interface. Il ne peut pas intercepter directement les appels de méthode des classes qui n'implémentent pas l'interface.
- L'objet proxy créé par JDK Proxy implémente l'interface implémentée par la classe cible, de sorte que l'objet proxy ne peut appeler que les méthodes définies dans l'interface.
4.3 Proxy dynamique CGLIB
CGLIB est une puissante bibliothèque tierce permettant de sous-classer des classes au moment de l'exécution afin d'implémenter des proxys. Sa principale caractéristique est qu'il peut générer dynamiquement une sous-classe d'une classe au moment de l'exécution sans nécessiter que la classe cible implémente une interface, afin d'intercepter et d'améliorer l'appel de méthode de la classe cible.
Caractéristiques et avantages de CGLIB :
- CGLIB peut proxy des classes qui n'implémentent pas d'interface. Cela le rend adapté à un plus large éventail de scénarios, y compris les classes sans interfaces.
- CGLIB utilise le mécanisme d'héritage pour implémenter des proxys, générer des sous-classes de la classe cible et insérer une logique transversale dans les sous-classes. Par conséquent, il peut intercepter toutes les méthodes de la classe cible, qu’il s’agisse de méthodes d’instance ou de méthodes statiques.
- En raison de l'utilisation de l'héritage pour générer des classes proxy, CGLIB ne peut pas utiliser
final
les méthodes proxy déclarées comme . C’est une limitation dont il faut être conscient. - Les proxys de CGLIB sont généralement légèrement plus lents que JDK Proxy car ils impliquent la création et le chargement du bytecode des classes proxy.
4.4 Différence entre le proxy JDK et le proxy dynamique CGLIB
Lorsque vous utilisez Spring AOP pour créer un proxy, vous pouvez choisir d'utiliser JDK Proxy ou CGLIB pour implémenter un proxy dynamique. Il existe quelques différences entre ces deux méthodes de proxy, voici un résumé de celles-ci :
Proxy JDK:
- Basé sur l'implémentation de classe dans la bibliothèque standard Java
java.lang.reflect.Proxy
. - Il est nécessaire que la classe cible implémente au moins une interface, car elle crée un proxy basé sur l'interface.
- En implémentant la méthode de l'interface proxy, la logique transversale est insérée avant et après l'appel de méthode.
- L'interface étant utilisée comme base du proxy, l'objet proxy généré ne peut appeler que les méthodes définies dans l'interface.
- En général, les performances de JDK Proxy sont relativement élevées.
CGLIB:
- est une bibliothèque tierce permettant de générer des sous-classes de classes implémentant des proxys au moment de l'exécution.
- La classe cible n'a pas besoin d'implémenter l'interface et la classe qui n'implémente pas l'interface peut être proxy.
- Grâce au mécanisme d'héritage, la logique transversale est insérée dans la sous-classe de la classe cible.
- Possibilité d'intercepter toutes les méthodes de la classe cible, y compris les méthodes d'instance et les méthodes statiques.
final
CGLIB ne peut pas déclarer de méthodes proxy en raison de l'utilisation de l'héritage et de la génération de bytecode des classes proxy .- Les proxys sont relativement lents en raison du bytecode impliqué dans la génération et le chargement des classes proxy.
comment choisir:
- Si la classe cible implémente l’interface, le proxy JDK est préféré. Il offre des performances supérieures et convient aux proxys basés sur une interface.
- Si la classe cible n'implémente pas l'interface, ou si vous devez intercepter des classes qui n'implémentent pas l'interface, vous pouvez choisir d'utiliser CGLIB. Il est plus flexible et applicable à un plus large éventail de scénarios de proxy.