2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Le proxy fait référence à un mode dans lequel un objet A peut avoir le même comportement que B en détenant un autre objet B. Afin d'ouvrir le protocole au monde extérieur, B implémente souvent une interface, et A implémentera également l'interface. Mais B est la classe d’implémentation « réelle », tandis que A est plus « virtuelle ». Elle emprunte les méthodes de B pour implémenter les méthodes d’interface. Bien que A soit une « pseudo-armée », elle peut améliorer B et faire d'autres choses avant et après avoir appelé la méthode de B. Spring AOP utilise des proxys dynamiques pour compléter le « tissage » dynamique du code.
Les avantages de l'utilisation d'un proxy vont au-delà. Si un projet s'appuie sur l'interface fournie par un autre projet, mais que l'interface de l'autre projet est instable et que le protocole est souvent modifié, vous pouvez utiliser un proxy lorsque l'interface change. il suffit de modifier le proxy, pas un par un. En ce sens, nous pouvons faire cela pour toutes les interfaces qui s’adaptent au monde extérieur pour empêcher le code extérieur d’envahir notre code. C’est ce qu’on appelle la programmation défensive. Il peut exister de nombreuses autres applications de proxy.
Dans l'exemple ci-dessus, la classe A est codée en dur pour contenir B, qui est le proxy statique de B. Si l'objet d'un proxy est incertain, il s'agit d'un proxy dynamique. Il existe actuellement deux implémentations courantes de proxy dynamique, le proxy dynamique jdk et le proxy dynamique cglib.
Le proxy statique est un modèle de conception et un type de modèle de proxy. Dans un proxy statique, la classe proxy a été définie avant l'exécution du programme et la relation entre la classe proxy et la classe proxy est déterminée au moment de la compilation. Cela signifie que la classe proxy et la classe proxy implémentent la même interface ou héritent de la même classe parent. La classe proxy contient en interne une instance de la classe proxy et appelle les méthodes de la classe proxy dans sa propre méthode. , il peut ajouter certaines de vos propres opérations avant et après l'appel, telles que la journalisation, la vérification des autorisations, le traitement des transactions, etc.
Le proxy statique comporte trois composants : une interface abstraite, une classe proxy et une classe proxy. Ses exemples d'implémentation sont les suivants :
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class TargetProxy implements TargetInteface {
-
- private Target target =new Target();
- @Override
- public void method1() {
- System.out.println("执行方法前...");
- target.method1();
- System.out.println("执行方法后...");
- }
-
- @Override
- public void method2() {
- System.out.println("执行方法前...");
- target.method2();
- System.out.println("执行方法后...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("执行方法前...");
- int method3 = target.method3(i);
- System.out.println("执行方法后...");
- return method3;
- }
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println(" Target method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("Target method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("Target method3 running ...");
- return i;
- }
- }
- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = new TargetProxy();
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Sortie du résultat :
Avant d'exécuter la méthode...
Méthode cible 1 en cours d'exécution ...
Après avoir exécuté la méthode...
-----------------------------
Avant d'exécuter la méthode...
Méthode cible 2 en cours d'exécution ...
Après avoir exécuté la méthode...
-----------------------------
Avant d'exécuter la méthode...
Méthode cible 3 en cours d'exécution ...
Après avoir exécuté la méthode...
3
Il n'est pas difficile de voir à partir de la mise en œuvre d'agents statiques que les avantages des agents statiques sont une mise en œuvre simple et facile à comprendre. Mais ses inconvénients sont également évidents, c'est-à-dire que chaque fois que vous devez ajouter une fonctionnalité proxy à une nouvelle classe, vous devez créer manuellement une nouvelle classe proxy, ce qui entraînera une forte augmentation du nombre de classes et une augmentation des coûts de maintenance. . Dans le même temps, le degré de couplage entre la classe proxy et la classe proxy est trop élevé. Lorsque des méthodes sont ajoutées, supprimées ou modifiées dans la classe proxy, les méthodes correspondantes doivent également être ajoutées, supprimées ou modifiées dans la classe proxy. , ce qui améliore le coût de maintenance du code. Un autre problème est que lorsque l'objet proxy proxy les classes d'implémentation de plusieurs interfaces cibles, il doit y avoir différentes méthodes dans les multiples classes d'implémentation. Puisque l'objet proxy doit implémenter la même interface que l'objet cible (en fait une relation d'inclusion), il doit le faire. être écrit De nombreuses méthodes peuvent facilement conduire à un code volumineux et difficile à maintenir.
L'idée principale du proxy dynamique est d'accéder indirectement à l'objet d'origine via l'objet proxy sans modifier le code de l'objet d'origine et d'effectuer des opérations supplémentaires avant et après l'accès.
Le principe de mise en œuvre du proxy dynamique repose principalement sur le mécanisme de réflexion de Java. Lorsque vous utilisez des proxys dynamiques, vous devez définir une interface ou un ensemble d'interfaces qui définissent le comportement de la classe proxy (objet proxy).Ensuite, vous devez écrire une implémentationInvocationHandler
Classe d'interface, cette classe contient une logique qui est exécutée avant et après les appels de méthode sur l'objet proxy.en appelantProxy.newProxyInstance()
méthode, passez le chargeur de classe de l'interface, le tableau d'interface etInvocationHandler
Objet, Java générera dynamiquement une classe proxy qui implémentera l'interface spécifiée au moment de l'exécution et déléguera les appels de méthode àInvocationHandler
objets à traiter.Lorsqu'une méthode d'un objet proxy est appelée, elle appelle en faitInvocationHandler
Interfaceinvoke()
Méthode, dans laquelle vous pouvez effectuer une logique de prétraitement basée sur le nom de la méthode, les paramètres et d'autres informations, puis appeler la méthode correspondante de l'objet proxy par réflexion.
Ensuite, nous introduisons deux proxys dynamiques : JDK Proxy et CGLib
JDK Proxy utilise le mécanisme de réflexion de Java pour générer dynamiquement des classes proxy. Spécifiquement,Proxy
la classe utiliseraProxyGenerator
(bien que cette classe ne soit pas une API publique, c'est la clé pour implémenter le proxy dynamique dans le JDK) pour générer le bytecode de la classe proxy et le charger dans la JVM.La classe proxy générée héritera dejava.lang.reflect.Proxy
classe et implémente l’interface spécifiée.Dans la méthode de la classe proxy, elle sera appeléeInvocationHandler
deinvoke
Méthode, transmet l'appel de méthode au processeur pour traitement.
De plus, afin d'améliorer les performances, JDK Proxy fournit également un mécanisme de mise en cache pour mettre en cache l'objet Class de la classe proxy générée. De cette façon, lorsque vous devez créer un objet proxy du même type, vous pouvez directement obtenir l'objet Class de la classe proxy depuis le cache sans le régénérer.La mise en cache se fait viaWeakCache
Implémenté par la classe, il utilise des références faibles aux objets du cache afin que les éléments du cache qui ne sont plus utilisés puissent être automatiquement nettoyés lorsque la JVM effectue un garbage collection.
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
InvocationHandler
interface et réécritureinvoke
méthode.existerinvoke
Dans la méthode, vous pouvez ajouter une logique personnalisée, telle que la journalisation, la vérification des autorisations, etc., et appeler la méthode de classe d'origine par réflexion.Proxy.newProxyInstance
méthode, en passant le chargeur de classe, le tableau d'interface etInvocationHandler
Instance pour générer dynamiquement des objets proxy. Cette méthode renvoie une instance de classe proxy qui implémente l'interface spécifiée.- public class TargetProxy {
- public static <T> Object getTarget(T t) {
- //新构建了一个 新的 代理类的对象
- return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
- //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
- System.out.println("执行方法前...");
- Object invoke = method.invoke(t, args);
- System.out.println("执行方法后...");
- return invoke;
- }
- });
- }
- }
InvocationHandler
deinvoke
Méthode, après avoir exécuté une logique personnalisée dans cette méthode, appelez la méthode de la classe d'origine.- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Sortie du résultat :
Avant d'exécuter la méthode...
méthode 1 en cours d'exécution ...
Après avoir exécuté la méthode...
-----------------------------
Avant d'exécuter la méthode...
méthode 2 en cours d'exécution ...
Après avoir exécuté la méthode...
-----------------------------
Avant d'exécuter la méthode...
méthode 3 en cours d'exécution ...
Après avoir exécuté la méthode...
3
MethodInterceptor
interface pour définir un intercepteur de méthode, qui exécutera une logique personnalisée avant et après l'appel de méthode de l'objet proxy, comme le prétraitement, le post-traitement, la gestion des exceptions, etc.- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- public class Target {
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
MethodInterceptor
classe d'interface et remplacementintercept
méthode. Écrivez la logique du proxy dans cette méthode.Enhancer
classe pour créer des objets proxy.Vous devez définir la classe proxy (viasetSuperclass
méthode) et les rappels (viasetCallback
Method définit la classe d’implémentation de MethodInterceptor).- public class TargetProxy {
- public static <T> Object getProxy(T t) {
- Enhancer en = new Enhancer(); //帮我们生成代理对象
- en.setSuperclass(t.getClass());//设置要代理的目标类
- en.setCallback(new MethodInterceptor() {//代理要做什么
- @Override
- public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("执行方法前。。。");
- //调用原有方法
- Object invoke = methodProxy.invokeSuper(object, args);
- // Object invoke = method.invoke(t, args);// 作用等同与上面。
- System.out.println("执行方法后。。。");
- return invoke;
- }
- });
- return en.create();
- }
- }
intercept
Logique proxy dans les méthodes.- public class TargetUser {
-
- public static void main(String[] args) {
- Target target = (Target) TargetProxy.getProxy(new Target());
- System.out.println(target.getClass().getName());
- target.method1();
- }
-
- }
Sortie du résultat :
com.heaboy.aopdemo.cglibproxy.CibleEnhunncetlBetCgLjeBf9f41fb8
avant d'exécuter la méthode. . .
méthode 1 en cours d'exécution ...
Après avoir exécuté la méthode. . .
avantage:
défaut:
Type d'objet proxy :JDK Proxy ne peut proxy que les classes qui implémentent des interfaces ; tandis que CGLib peut directement proxy les classes ordinaires.
performance: CGLib génère des sous-classes de classes proxy au moment de l'exécution et est généralement considéré comme ayant des performances légèrement meilleures que JDK Proxy. Mais dans la plupart des scénarios, cette différence de performances n’est pas significative.
scènes à utiliser : Si l'objet cible implémente déjà l'interface, l'utilisation du proxy JDK est un choix simple et direct. Si vous devez proxy une classe qui n'implémente pas d'interface, vous devez utiliser CGLib.
compter sur:JDK Proxy ne nécessite aucune dépendance supplémentaire car il fait partie de la bibliothèque principale Java ; tandis que CGLib nécessite l'ajout de la bibliothèque CGLib en tant que dépendance du projet.
JDK Proxy est une fonction fournie avec le langage Java et n'a pas besoin d'être implémentée en chargeant des classes tierces ;
Java fournit une prise en charge stable du proxy JDK et continuera à mettre à niveau et à mettre à jour le proxy JDK. Par exemple, les performances du proxy JDK dans la version Java 8 ont été considérablement améliorées par rapport aux versions précédentes ;
JDK Proxy est implémenté via des intercepteurs et une réflexion ;
JDK Proxy ne peut proxy que les classes qui héritent des interfaces ;
JDK Proxy est relativement simple à implémenter et à appeler ;
CGLib est un outil fourni par un tiers, implémenté sur la base d'ASM, et doté de performances relativement élevées ;
CGLib n'a pas besoin d'être implémenté via une interface, il est appelé en implémentant une sous-classe.
Proxy statique : Les proxys statiques sont déterminés lors de la compilation.Une classe proxy doit être écrite pour chaque classe proxy et la classe proxy implémentent la même interface ou héritent de la même classe parent.
La classe proxy d'un proxy statique existe au moment de la compilation, elle ne peut donc proxy que des classes spécifiques lorsque le programme est en cours d'exécution et ne peut pas décider dynamiquement quelles classes proxy.
Le proxy statique encapsule l'appel de méthode de l'objet d'origine et peut ajouter une logique supplémentaire avant et après l'appel, mais la classe proxy doit être écrite à l'avance, ce qui augmentera la quantité de code.
Le proxy statique spécifie explicitement l'objet proxy dans le code et est relativement intuitif à utiliser, mais l'ajout de nouvelles classes proxy nécessite une recompilation.
Proxy dynamique : Le proxy dynamique crée des objets proxy au moment de l'exécution sans écrire de classes proxy à l'avance. Utilisez le mécanisme de réflexion de Java pour générer dynamiquement des classes proxy et des objets proxy.
Les proxys dynamiques sont basés sur des interfaces et sont implémentés via la classe java.lang.reflect.Proxy et l'interface java.lang.reflect.InvocationHandler.
Le proxy dynamique peut proxy des classes de plusieurs interfaces et décider dynamiquement quelles classes proxy. Au moment de l'exécution, des proxys peuvent être générés pour différents objets selon les besoins, offrant ainsi une plus grande flexibilité.
Le proxy dynamique n'a pas besoin d'écrire une classe de proxy spécifique pour chaque classe de proxy, ce qui est plus flexible et enregistre le code.
Les agents dynamiques peuvent ajouter une logique personnalisée avant et après les appels de méthode sur l'objet proxy, comme la journalisation, la gestion des transactions, etc. L'inconvénient du proxy dynamique est que, par rapport au proxy statique, la génération d'un objet proxy au moment de l'exécution nécessite une certaine surcharge de performances.
Les proxys statiques conviennent aux scénarios suivants :
Lorsque le nombre d'objets cibles (objets proxy) est limité et déterminé, un proxy statique peut être implémenté en écrivant manuellement des classes proxy. Les proxys statiques créent des classes proxy au moment de la compilation, afin d'offrir de meilleures performances au moment de l'exécution.
Les proxys statiques encapsulent l'objet cible et ajoutent des fonctions supplémentaires sans modifier le code d'origine. Cela rend les proxys statiques souvent utilisés pour des problèmes transversaux tels que la journalisation et la gestion des transactions.
Le proxy dynamique convient aux scénarios suivants :
Lorsque le nombre d'objets cibles est incertain ou ne peut pas être déterminé à l'avance, les proxys dynamiques peuvent générer plus facilement des objets proxy. Il génère des classes proxy et des objets proxy au moment de l'exécution, évitant ainsi le travail fastidieux d'écriture manuelle de plusieurs classes proxy.
Les proxys dynamiques offrent la flexibilité nécessaire pour ajouter, supprimer ou modifier le comportement du proxy pour les objets cibles au moment de l'exécution. Cela rend les proxys dynamiques souvent utilisés dans des scénarios d'application tels que AOP (programmation orientée aspect) et RPC (appel de procédure à distance).
Il convient de noter que, étant donné que les proxys dynamiques créent des classes proxy et des objets proxy via le mécanisme de réflexion au moment de l'exécution, leurs performances peuvent être légèrement inférieures à celles des proxys statiques. De plus, les proxys dynamiques ne peuvent cibler que les objets qui implémentent l'interface, tandis que les proxys statiques n'ont pas cette restriction.
En résumé, les proxys statiques conviennent aux scénarios où le nombre d'objets cibles est limité et certain, et nécessitent une encapsulation et des fonctions supplémentaires, tandis que les proxys dynamiques conviennent aux scénarios où le nombre d'objets cibles est incertain ou ne peut pas être déterminé à l'avance. et le comportement du proxy doit être ajouté, supprimé ou modifié de manière flexible. Choisissez la méthode d’agence appropriée en fonction des besoins et des circonstances spécifiques.
Spring AOP est un module important du framework Spring, utilisé pour implémenter une programmation orientée aspect.
Programmation en face à face , il s'agit d'un modèle de programmation qui permet aux programmeurs de modulariser via des points transversaux personnalisés et d'encapsuler les comportements qui affectent plusieurs classes dans des modules réutilisables. Exemple : Par exemple, pour la sortie du journal, si vous n'utilisez pas AOP, vous devez placer les instructions de sortie du journal dans toutes les classes et méthodes. Cependant, avec AOP, vous pouvez encapsuler les instructions de sortie du journal dans un module réutilisable et les placer dans un module. de manière déclarative. Dans une classe, la sortie du journal est automatiquement complétée à chaque fois que la classe est utilisée.
Dans l'idée de programmation orientée aspect, les fonctions sont divisées en deux types
Activité principale: La connexion, l'enregistrement, l'ajout, la suppression, la modification et la requête sont tous appelés cœur de métier
Fonctions périphériques: Les journaux et la gestion des transactions sont des services périphériques secondaires.
Dans la programmation orientée aspect, les fonctions métier principales et les fonctions périphériques sont développées indépendamment, et les deux ne sont pas couplées. Ensuite, les fonctions aspect et les fonctions métier principales sont « tissées » ensemble, ce qu'on appelle AOP.
AOP peut convertir ceux qui ne sont pas liés à l'entreprise,Mais il est encapsulé pour la logique ou les responsabilités (telles que le traitement des transactions, la gestion des journaux, le contrôle des autorisations, etc.) communément appelées par les modules métier.,facile deRéduire le code en double dans le système,Réduire le couplage entre les modules,etPropice à l’évolutivité et à la maintenabilité futures。
Il existe les concepts suivants dans AOP :
AspectJ: L'aspect n'est qu'un concept. Il n'y a pas d'interface ou de classe spécifique qui lui correspond. C'est un nom collectif pour Join point, Advice et Pointcut.
Point de jonction : Le point de connexion fait référence à un point lors de l'exécution du programme, tel que l'invocation de méthode, la gestion des exceptions, etc. Dans Spring AOP, seuls les points de jointure au niveau de la méthode sont pris en charge.
Conseil : La notification, c'est-à-dire la logique transversale dans un aspect que nous définissons, est de trois types : « autour », « avant » et « après ». Dans de nombreux frameworks d'implémentation AOP, Advice agit généralement comme un intercepteur et peut également contenir de nombreux intercepteurs comme lien à traiter autour du point de jointure.
Point de coupe: Pointcut, utilisé pour faire correspondre les points de jointure contenus dans un AspectJ qui doivent être filtrés par Pointcut.
Introduction : Introduction, permettant à un aspect de déclarer que les objets conseillés implémentent toutes les interfaces supplémentaires qu'ils n'implémentent pas réellement. Par exemple, un objet proxy peut être utilisé pour proxy deux classes cibles.
Tissage : Tissage, maintenant que nous avons les points de connexion, les points de coupure, les notifications et les aspects, comment les appliquer au programme ? C'est vrai, c'est du tissage. Sous la direction de pointscuts, la logique de notification est insérée dans la méthode cible, afin que notre logique de notification puisse être exécutée lorsque la méthode est appelée.
Proxy AOP : Le proxy AOP fait référence à l'objet qui implémente le protocole d'aspect dans le cadre d'implémentation AOP. Il existe deux types de proxys dans Spring AOP, à savoir le proxy dynamique JDK et le proxy dynamique CGLIB.
Objet cible: L'objet cible est l'objet proxy.
Spring AOP est implémenté sur la base du proxy dynamique JDK et de la promotion Cglib. Les deux méthodes de proxy sont des méthodes d'exécution, elles n'ont donc pas de traitement au moment de la compilation, donc Spring est implémenté via du code Java.
Certains comportements courants dispersés entre plusieurs classes ou objets (tels que la journalisation, la gestion des transactions, le contrôle des autorisations, la limitation du courant d'interface, la puissance de l'interface, etc.), ces comportements sont généralement appelés préoccupations transversales . Si nous implémentons ces comportements de manière répétée dans chaque classe ou objet, cela conduira à un code redondant, complexe et difficile à maintenir.
AOP peut transformer des préoccupations transversales (telles que la journalisation, la gestion des transactions, le contrôle des autorisations, la limitation du courant d'interface, la puissance de l'interface, etc.) Logique métier de base (préoccupations fondamentales, préoccupations fondamentales) Séparez-vous du focus pour parvenir à la séparation des préoccupations.
Journalisation : personnalisez les annotations de journalisation et utilisez AOP pour réaliser la journalisation avec une seule ligne de code.
Statistiques de performances : utilisez AOP pour compter le temps d'exécution de la méthode avant et après l'exécution de la méthode cible afin de faciliter l'optimisation et l'analyse.
Gestion des transactions:@Transactional
Les annotations permettent à Spring d'effectuer la gestion des transactions pour nous, comme l'annulation des opérations d'exception, éliminant ainsi la logique de gestion des transactions répétées.@Transactional
Les annotations sont implémentées sur la base de l'AOP.
Contrôle des autorisations : utilisez AOP pour déterminer si l'utilisateur dispose des autorisations requises avant d'exécuter la méthode cible. Si tel est le cas, exécutez la méthode cible, sinon elle ne s'exécutera pas.Par exemple, SpringSecurity utilise@PreAuthorize
Vous pouvez personnaliser la vérification des autorisations en commentant une ligne de code.
Limitation de courant d'interface : utilisez AOP pour limiter la demande via des algorithmes et des implémentations de limitation de courant spécifiques avant l'exécution de la méthode cible.
Gestion du cache : utilisez AOP pour lire et mettre à jour le cache avant et après l'exécution de la méthode cible.
Les méthodes d'implémentation courantes d'AOP incluent le proxy dynamique, l'opération de bytecode, etc.
Spring AOP est basé sur un proxy dynamique. Si l'objet à proxy implémente une certaine interface, Spring AOP l'utilisera. Proxy JDK, pour créer un objet proxy. Pour les objets qui n'implémentent pas l'interface, vous ne pouvez pas utiliser le proxy JDK. Pour le moment, Spring AOP l'utilisera. Cglib Générer une sous-classe de l'objet proxy pour servir de proxy
existerspring-aop.xml
Configurer les beans et aspects associés dans le fichier de configuration
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- 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">
-
- <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
-
- <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
-
- <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="target"/> <!--被代理的类-->
- <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
- <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
- <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
- </bean>
- </beans>
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface{
-
- /*
- * 需要增强的方法,连接点JoinPoint
- **/
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
- public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
-
- /*
- * 通知/增强
- **/
- @Override
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- System.out.println("前置环绕通知");
- Object proceed = methodInvocation.proceed();
- System.out.println("后置环绕通知");
- return proceed;
- }
-
- @Override
- public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
- System.out.println("后置返回通知");
- }
-
- @Override
- public void before(Method method, Object[] args, Object target) throws Throwable {
- System.out.println("前置通知");
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
- TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
- targetProxy.method1();
- }
- }
Résultat de sortie :
Notification surround avant
Pré-notification
méthode 1 en cours d'exécution ...
notification après retour
Notification surround arrière
existerspring-confaop.xml
Configurer les beans et aspects associés dans le fichier de configuration
- <?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">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- /*
- * 目标类
- **/
- public class Target {
-
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- /*
- * 连接点JoinPoint
- **/
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- // int i1 = 1 / i;
- return i;
- }
- }
- import org.aspectj.lang.ProceedingJoinPoint;
- /*
- * 切面类
- **/
- public class TargetAspect {
-
- /*
- * 前置通知
- **/
- public void before() {
- System.out.println("conf前置通知");
- }
-
- public void after() {
- System.out.println("conf后置通知");
- }
-
- public void afterReturning() {
- System.out.println("conf后置返回通知");
- }
-
- public void afterThrowing(Exception ex) throws Exception {
- // System.out.println("conf异常通知");
- // System.out.println(ex.getMessage());
- }
-
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("conf环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("conf环绕后置");
- }
- return proceed;
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
- Target targetProxy = (Target) appCtx.getBean("target");
- System.out.println(targetProxy.method3(0));
- }
- }
Résultat de sortie :
conf pré-notification
préfixe surround conf
méthode 3 en cours d'exécution ...
conf notification post-retour
post de conf surround
notification après la conférence
0
- <?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">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TestAnnotation{
- }
- /*
- * 切面类
- **/
- @Aspect
- @Component
- public class AnnotationAspect {
-
- // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
- @Pointcut("@annotation(TestAnnotation)")
- private void advicePointcut() {}
-
- /*
- * 前置通知
- **/
- @Before("advicePointcut()")
- public void before() {
- System.out.println("annotation前置通知");
- }
-
- @After("advicePointcut()")
- public void after() {
- System.out.println("annotation后置通知");
- }
-
- @AfterReturning(pointcut = "advicePointcut()")
- public void afterReturning() {
- System.out.println("annotation后置返回通知");
- }
-
- @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
- public void afterThrowing(Exception ex) throws Exception {
- System.out.println("annotation异常通知");
- System.out.println(ex.getMessage());
- }
-
- @Around("advicePointcut()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("annotation环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("annotation环绕后置");
- }
- return proceed;
- }
- }
- @Controller
- public class TestController {
-
- @RequestMapping("/test.do")
- @ResponseBody
- public String testController() {
- TestController o = (TestController) AopContext.currentProxy();
- o.test();
- // System.out.println("tewt");
- return "ok";
- }
-
- @TestAnnotation
- public void test() {
- System.out.println("test running");
- }
-
- }