Maison >Java >javaDidacticiel >Explication détaillée de SpringAop en Java
J'ai étudié SpringAop ces derniers jours et j'ai trouvé des informations sur Internet
. AOP
AOP (Aspect Oriented Programming), qui est une programmation orientée aspect, peut être considérée comme le complément et l'amélioration de la POO (Object Oriented Programming). La POO introduit des concepts tels que l'encapsulation, l'héritage et le polymorphisme pour établir une hiérarchie d'objets utilisée pour simuler un ensemble de comportements publics. Cependant, la POO permet aux développeurs de définir des relations verticales, mais elle ne convient pas à la définition de relations horizontales, telles que les fonctions de journalisation. Le code de journalisation est souvent réparti horizontalement dans toutes les hiérarchies d'objets et n'a rien à voir avec les fonctionnalités de base de l'objet auquel il correspond. Il en va de même pour d'autres types de code, tels que la sécurité, la gestion des exceptions et la persistance transparente du code. est appelé cross-cut. Dans la conception POO, cela conduit à la duplication d'une grande quantité de code et n'est pas propice à la réutilisation de divers modules.
La technologie AOP est tout le contraire. Elle utilise une technologie appelée « transversale » pour disséquer l'intérieur de l'objet encapsulé et encapsuler les comportements publics qui affectent plusieurs classes dans un module réutilisable et le nommer « Aspect ». ", qui est l'aspect. Les soi-disant « aspects » sont simplement une logique ou des responsabilités encapsulées qui n'ont rien à voir avec le métier mais sont appelées conjointement par les modules métier, de manière à réduire la duplication de code dans le système, à réduire le couplage entre les modules et à faciliter l'opérabilité et la maintenabilité futures.
En utilisant la technologie « transversale », AOP divise le système logiciel en deux parties : Préoccupations principales et Préoccupations transversales. Le processus principal de traitement des affaires est la préoccupation centrale, et la partie qui a peu de relation avec lui est la préoccupation transversale. Une caractéristique des préoccupations transversales est qu'elles surviennent souvent à plusieurs endroits dans la préoccupation principale, et que les endroits sont fondamentalement similaires, comme l'authentification des autorités, les journaux et autres. Le rôle de l'AOP est de séparer les différentes préoccupations du système, en séparant les préoccupations centrales et les préoccupations transversales.
Concepts fondamentaux de l'AOP
1. Préoccupations transversales
Quelles méthodes doivent être interceptées et comment les gérer. après interception ? Ces préoccupations sont appelées préoccupations transversales
2. La classe aspect
est une abstraction des caractéristiques des objets, et l'aspect est une abstraction des préoccupations transversales
3. Joinpoint (joinpoint)
Point intercepté, car Spring ne prend en charge que les points de jointure de type méthode, donc dans Spring, le point de jointure fait référence à la méthode interceptée. champ ou constructeur
4. Pointcut (pointcut)
Définition des points de connexion intercepteurs
5. Conseil (conseil)
La soi-disant notification fait référence. au code à exécuter après avoir intercepté le point de connexion. Les notifications sont divisées en cinq catégories : notifications pré-, post-, d'exception, finales et environnantes
6. Objet cible
proxy Le objet cible
7. Weave
Le processus d'application des aspects à l'objet cible et provoquant la création de l'objet proxy
8 Introduction
Sans. en modifiant le code, introduisez des méthodes ou des champs qui peuvent être ajoutés dynamiquement à la classe pendant l'exécution
Prise en charge de Spring pour le support AOP
Le proxy AOP de Spring est généré et géré par le conteneur IOC de Spring, et ses dépendances sont également gérées par le conteneur IOC . Par conséquent, le proxy AOP peut utiliser directement d'autres instances de bean dans le conteneur comme cibles, et cette relation peut être fournie par l'injection de dépendances du conteneur IOC. Les règles de Spring pour créer un proxy sont :
1, Par défaut, le proxy dynamique Java est utilisé pour créer un proxy AOP , afin qu'un proxy puisse être créé pour n'importe quelle instance d'interface
2, Lorsque la classe qui a besoin d'un proxy n'est pas une interface proxy, Spring passera à l'utilisation du proxy CGLIB, ou vous pouvez forcer l'utilisation de CGLIB
La programmation AOP est en fait une question très simple. En ce qui concerne la programmation AOP, les membres des programmes ne doivent participer qu'à trois parties :
1. Définir les composants commerciaux communs
2. Définir les points d'entrée. composants métier
3. Définir le traitement amélioré. Le traitement amélioré est une action de traitement intégrée au cadre AOP pour les composants métier ordinaires
Par conséquent, la clé de la programmation AOP est de définir le point d'entrée et de définir. traitement amélioré. Une fois le point d'entrée approprié et le traitement amélioré définis, le framework AOP générera automatiquement un proxy AOP, c'est-à-dire : méthode d'objet proxy = traitement amélioré + objet proxy méthode.
Ce qui suit est un Spring AOP Implémentation simple d'AOP
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> </beans>
Notez qu'avant d'expliquer, laissez-moi vous expliquer une chose : pour utiliser Spring AOP, pour réussir à exécuter le code, c'est pas suffisant pour utiliser uniquement le package jar fourni par Spring aux développeurs. Veuillez vous connecter également en ligne : 1. 🎜> Commençons par expliquer l'implémentation XML à l'aide de Spring AOP. Définissez d'abord une interface :
Définissez deux classes d'implémentation d'interface :
Problèmes transversaux, voici le temps d'impression :1 public interface HelloWorld 2 { 3 void printHelloWorld(); 4 void doPrint(); 5 }
Écrivez une fonction principale pour l'appeler :
public class HelloWorldImpl1 implements HelloWorld { public void printHelloWorld() { System.out.println("Enter HelloWorldImpl1.printHelloWorld()"); } public void doPrint() { System.out.println("Enter HelloWorldImpl1.doPrint()"); return ; } }
public class HelloWorldImpl2 implements HelloWorld { public void printHelloWorld() { System.out.println("Enter HelloWorldImpl2.printHelloWorld()"); } public void doPrint() { System.out.println("Enter HelloWorldImpl2.doPrint()"); return ; } }Le résultat en cours d'exécution est :
CurrentTime = 1446129611993Enter HelloWorldImpl1.printHelloWorld() CurrentTime = 1446129611993CurrentTime = 1446129611994Enter HelloWorldImpl1.doPrint() CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.printHelloWorld() CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.doPrint() CurrentTime = 1446129611994
看到给HelloWorld接口的两个实现类的所有方法都加上了代理,代理内容就是打印时间
基于Spring的AOP使用其他细节
1、增加一个横切关注点,打印日志,Java类为:
public class LogHandler { public void LogBefore() { System.out.println("Log before method"); } public void LogAfter() { System.out.println("Log after method"); } }
aop.xml配置为:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" /> <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" /> <bean id="timeHandler" class="com.xrq.aop.TimeHandler" /> <bean id="logHandler" class="com.xrq.aop.LogHandler" /> <aop:config> <aop:aspect id="time" ref="timeHandler" order="1"> <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.*(..))" /> <aop:before method="printTime" pointcut-ref="addTime" /> <aop:after method="printTime" pointcut-ref="addTime" /> </aop:aspect> <aop:aspect id="log" ref="logHandler" order="2"> <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.*(..))" /> <aop:before method="LogBefore" pointcut-ref="printLog" /> <aop:after method="LogAfter" pointcut-ref="printLog" /> </aop:aspect> </aop:config> </beans>
测试类不变,打印结果为:
CurrentTime = 1446130273734 Log before method Enter HelloWorldImpl1.printHelloWorld() Log after method CurrentTime = 1446130273735 CurrentTime = 1446130273736 Log before method Enter HelloWorldImpl1.doPrint() Log after method CurrentTime = 1446130273736 CurrentTime = 1446130273736 Log before method Enter HelloWorldImpl2.printHelloWorld() Log after method CurrentTime = 1446130273736 CurrentTime = 1446130273737 Log before method Enter HelloWorldImpl2.doPrint() Log after method CurrentTime = 1446130273737
要想让logHandler在timeHandler前使用有两个办法:
(1)aspect里面有一个order属性,order属性的数字就是横切关注点的顺序,数字越大执行越靠后,后置通知相反。
(2)把logHandler定义在timeHandler前面,Spring默认以aspect的定义顺序作为织入顺序
2、我只想织入接口中的某些方法
修改一下pointcut的expression就好了:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" /> <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" /> <bean id="timeHandler" class="com.xrq.aop.TimeHandler" /> <bean id="logHandler" class="com.xrq.aop.LogHandler" /> <aop:config> <aop:aspect id="time" ref="timeHandler" order="1"> <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.print*(..))" /> <aop:before method="printTime" pointcut-ref="addTime" /> <aop:after method="printTime" pointcut-ref="addTime" /> </aop:aspect> <aop:aspect id="log" ref="logHandler" order="2"> <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.do*(..))" /> <aop:before method="LogBefore" pointcut-ref="printLog" /> <aop:after method="LogAfter" pointcut-ref="printLog" /> </aop:aspect> </aop:config> </beans>
表示timeHandler只会织入HelloWorld接口print开头的方法,logHandler只会织入HelloWorld接口do开头的方法
3、强制使用CGLIB生成代理
前面说过Spring使用动态代理或是CGLIB生成代理是有规则的,高版本的Spring会自动选择是使用动态代理还是CGLIB生成代理内容,当然我们也可以强制使用CGLIB生成代理,那就是5f4edcee1f0c5735c643ff3ca537e591里面有一个"proxy-target-class"属性,这个属性值如果被设置为true,那么基于类的代理将起作用,如果proxy-target-class被设置为false或者这个属性被省略,那么基于接口的代理将起作用。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!