Notes d'étude de printemps-04 AOP

1. Modèle d'agence

Le scénario applicable du mode proxy est que parfois nous voulons améliorer les méthodes de certaines classes d'entités, mais il n'est pas pratique de modifier les définitions de méthode correspondantes dans les classes d'entités. À ce stade, nous pouvons écrire la partie améliorée dans le proxy à travers le mode.

1) proxy statique

Supposons que nous voulions vendre des téléphones mobiles, afin que nous puissions écrire la classe d'entité comme suit:

Person.java

public class Person {
    public void sellPhone(){
        System.out.println("卖手机");
    }
}

tester:

public class TestStaticProxy {
    public static void main(String[] args) {
        Person person = new Person();
        person.sellPhone();
    }
}

Nous constatons maintenant que nous devons trouver la prochaine maison avant de vendre des téléphones portables, mais nous avons défini la méthode de vente des téléphones mobiles. À ce stade, nous pouvons l'améliorer grâce à un proxy statique:

1) Utiliser les spécifications de définition d'interface

public interface ISellPhone {
    public void sellPhone();
}

2) Méthode de définition

public class Person implements ISellPhone {
    public void sellPhone(){
        System.out.println("卖手机");
    }
}

3) Améliorer les méthodes grâce aux agents

public class SellPhoneProxy implements ISellPhone {
    private Person person = new Person();
    public void sellPhone() {
        System.out.println("寻找买家");
        person.sellPhone();
    }
}

4) Nous utilisons simplement le proxy directement

public class TestStaticProxy {
    public static void main(String[] args) {
        ISellPhone iSellPhone = new SellPhoneProxy();
        iSellPhone.sellPhone();
    }
}

2) proxy dynamique JDK

L'inconvénient des agents statiques est que pour presque toutes les entreprises, ils doivent être effectués en ajoutant un agent, même si leurs méthodes d'amélioration sont presque les mêmes; nous pouvons également utiliser des agents dynamiques pour améliorer directement la méthode sans écrire beaucoup de classe d'agents .

Nous ajoutons une activité après-vente de téléphonie mobile:

public interface ISellPhone {
    public void sellPhone();
    public void serviceAfterSelling();
}

Person.java

public class Person implements ISellPhone {
    public void sellPhone(){
        System.out.println("卖手机");
    }

    public void serviceAfterSelling() {
        System.out.println("售后服务");
    }
}

Utilisez l'interface proxy dynamique de JDK:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class SellPhoneProxy implements InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用前");
        Object result = method.invoke(new Person(),args);
        System.out.println("调用后");
        return result;
    }
}

En voyant le nom du package, nous devons également savoir que le proxy dynamique est implémenté via un mécanisme de réflexion. La propriété Object est utilisée pour stocker l'objet mandaté.

tester:

import java.lang.reflect.Proxy;

public class TestDynamicProxy {
    public static void main(String[] args) {
        Person person = new Person();
        ISellPhone iSellPhone = (ISellPhone) Proxy.newProxyInstance(ISellPhone.class.getClassLoader(),new Class[]{ISellPhone.class},new SellPhoneProxy());
        iSellPhone.serviceAfterSelling();
    }
}

[Note]: Qu'il s'agisse d'un proxy statique ou d'un proxy dynamique, la classe proxy et la classe proxy doivent avoir une interface commune.

3) Agent dynamique CGLib

Bien sûr, vous pouvez également utiliser la méthode d'héritage, laisser la classe proxy hériter de la classe proxy et améliorer la méthode correspondante pour proxy (cglib) en écrasant la méthode.

A. Importer les dépendances

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

B. Utiliser le proxy dynamique cglib

import java.lang.reflect.Method;

public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Person.class);
        enhancer.setCallback(new InvocationHandler() {
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("执行前");
                Object invoke = method.invoke(new Person(),objects);
                System.out.println("执行后");
                return invoke;
            }
        });
        Person personAgent = (Person) enhancer.create();
        personAgent.sellPhone();
        System.out.println("============");
        personAgent.serviceAfterSelling();
    }
}

3. Résultats de l'exécution

2. Programmation orientée aspect AOP

La programmation orientée aspect AOP (Aspect Oriented Programming) est principalement utilisée pour résoudre certains problèmes au niveau du système dans le processus de développement du programme, tels que les journaux, les transactions, les autorisations, etc.

L'AOP de Spring est en fait une amélioration du proxy de la méthode.Après l'analyse ci-dessus, nous savons déjà que le proxy basé sur l'interface utilise le JDK; s'il n'y a pas d'interface, le proxy est utilisé par cglib.

Examinons d'abord la programmation orientée objet (programmation orientée objet). Tout est considéré comme un objet. Java est un langage OOP. L'extension des classes est réalisée par héritage. Le système construit avec Java montre une relation verticale.

Cependant, l'héritage présente également des lacunes. Bien que l'héritage puisse compléter l'amélioration de la méthode de classe parente, chaque amélioration de la classe nécessite un héritage, ce qui entraînera un trop grand nombre de classes dans l'ensemble du système, ce qui n'est pas facile à gérer, en particulier pour tous. comme les journaux. Lorsque la méthode et la méthode d’amélioration sont presque identiques, si elle est implémentée par héritage, la charge de travail est trop importante.

Dans Sring, une technologie "transversale" est définie, qui est améliorée en insérant une section transversale dans la méthode sans héritage. L'ensemble du système présente une relation horizontale et la couche inférieure est réalisée par un agent, qui a une croix -section. L'effet est le suivant:

A. Terminologie relative à l'AOP:

1. Notification, traitement amélioré (avis)

Le code ou la logique écrite pour implémenter les améliorations fonctionnelles est la sécurité, la transaction, le journal, etc. mentionné ci-dessus.

2. Point de connexion (JoinPoint)

Spring permet l'insertion de notifications, y compris l'avant, l'arrière, l'entourage (avant et après) de chaque méthode, et lorsqu'une exception est levée, Spring prend uniquement en charge le point de connexion de la méthode.

3. PointCut

Autrement dit, nous définissons en fait les points de connexion à utiliser, c'est-à-dire les points de connexion qui coupent réellement la notification.

4. Aspect (Aspect)

L'aspect est la combinaison de la notification et du point d'entrée. La notification est chargée d'expliquer ce qu'il faut faire et quand le faire, et le point d'entrée indique où le faire, qui constituent ensemble l'aspect.

5. Introduction

L'introduction nous permet d'introduire des aspects dans la classe cible.

6. Cible

La classe cible mentionnée dans l'introduction, c'est-à-dire l'objet à notifier, a une réelle logique métier. Elle n'a pas besoin de prêter attention à ce qui est coupé, mais seulement de faire attention à sa propre logique métier.

7. Tissage

Processus d'application de l'aspect à l'objet cible (coupure de la notification au point de contact) et création d'un nouvel objet proxy en conséquence.

B. Ressentez l'utilisation de l'AOP (annotation):

1. Ajouter des fichiers d'en-tête

<?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"
       xsi:schemaLocation="
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd">
    
</beans>

2. Importez les dépendances tissées

        <!--引入织入相关的依赖-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

3. Ajoutez deux méthodes à améliorer

AdminService.java

package com.zt.Service;

import org.springframework.stereotype.Service;

@Service
public class AdminService {

    public Integer getAdmin(){
        System.out.println("-----getAdmin-----");
        return 100;
    }

}

UserService.java

package com.zt.Service;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public void getUser(){
        System.out.println("-----getUser-----");
    }

}

4. Écrivez la classe d'aspect

package com.zt.Aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogAdvice {

    @Before("execution(* com.zt.Service.*.*(..))")
    public void before(){
        System.out.println("-----方法执行前 before -----");
    }

    @After("execution(* com.zt.Service.*.*(..))")
    public void after(){
        System.out.println("-----方法执行后 after -----");
    }

    @AfterReturning("execution(* com.zt.Service.*.*(..))")
    public void afterReturning(){
        System.out.println("-----方法执行返回后 afterReturning -----");
    }

    @Around("execution(* com.zt.Service.*.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("-----环绕前-----");
        System.out.println("方法名:" + joinPoint.getSignature());
        Object proceed = joinPoint.proceed();
        System.out.println("-----环绕后-----");
        System.out.println(proceed);
    }

    @AfterThrowing("execution(* com.zt.Service.*.*(..))")
    public void afterThrow(){
        System.out.println("-----有异常-----");
    }

}

[Note]: L'expression d'exécution est utilisée pour spécifier les méthodes améliorées.

Bien sûr, nous pouvons également spécifier la méthode à améliorer: execution (void com.zt.Service.UserService.getUser (..))

 

5. Comme nous utilisons la méthode de classe d'aspect, nous devons activer l'analyse des paquets et laisser le conteneur Spring gérer le Bean utilisé pour la configuration

<context:component-scan base-package="com.zt"/>

6. Activer la prise en charge des annotations pour le proxy automatique AOP

<aop:aspectj-autoproxy/>

7. Utilisez les classes de configuration et testez

package com.zt.Config;

import com.zt.Service.AdminService;
import com.zt.Service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class JavaConfig {

    @Autowired
    private UserService userService;

    @Autowired
    private AdminService adminService;

    @Test
    public void TestAop(){
        userService.getUser();
        System.out.println("-------------------------------------------");
        adminService.getAdmin();
    }

}

[Note]: Spring ne peut améliorer la méthode Bean que dans le conteneur, et l'objet instancié en dehors du conteneur ne sera pas amélioré.

C. Utilisation d'AOP (méthode du fichier de configuration)

1. Définissez la classe d'aspect

package com.zt.Aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Component
public class XMLAdvice {

    public void before(){
        System.out.println("-----方法执行前 before -----");
    }

    public void after(){
        System.out.println("-----方法执行后 after -----");
    }

    public void afterReturning(){
        System.out.println("-----方法执行返回后 afterReturning -----");
    }

    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("-----环绕前-----");
        System.out.println("方法名:" + joinPoint.getSignature());
        Object proceed = joinPoint.proceed();
        System.out.println("-----环绕后-----");
        System.out.println("方法执行结果的返回值:" + proceed);
    }

    public void afterThrow(){
        System.out.println("-----有异常-----");
    }
    
}

2. Dans le fichier de configuration, utilisez des pointcuts et reportez-vous aux aspects à tisser

    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.zt.Service.*.*(..))"/>
        <aop:aspect ref="XMLAdvice">
            <aop:before pointcut-ref="pointcut" method="before"/>
            <aop:after pointcut-ref="pointcut" method="after"/>
        </aop:aspect>
    </aop:config>

<aop: pointcut>: Utilisé pour définir le point de coupe.

<aop: aspect>: Utilisé pour introduire des classes d'aspect.

<aop: before>: définit le mode d'exécution comme avant l'exécution. Pour introduire un pointcut, vous pouvez soit utiliser ref pour faire référence à un pointcut existant (pointcut-ref), soit utiliser directement une expression d'exécution pour définir un pointcut. méthode est utilisée pour spécifier la méthode dans l'aspect d'où provient la notification, et les autres méthodes d'exécution sont similaires.


        <aop:aspect ref="XMLAdvice">
            <aop:before pointcut="execution(* com.zt.Service.*.*(..))" method="before"/>
            <aop:after pointcut="execution(* com.zt.Service.*.*(..))" method="after"/>
        </aop:aspect>

D. Utilisation de l'AOP (utiliser la notification directement, en implémentant certaines interfaces spécifiques)

LogBefore.java

package com.zt.Aop;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class LogBefore implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("-----before------" + method.getName() + "-----");
    }
}

LogAfter.java

package com.zt.Aop;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class LogAfter implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("-----after-----" + method.getName() + "------");
    }
}

Référence dans le fichier de configuration:

    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.zt.Service.*.*(..))"/>
        <aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="logAfter" pointcut-ref="pointcut"/>
    </aop:config>

[Note]: Utilisez l'annotation @Component pour que Spring instancie et gère automatiquement ce bean, et le nom par défaut est en minuscules, et les autres restent inchangés (nom de cas de camel). Bien sûr, pour la lisibilité, nous pouvons également spécifier l'id du bean injecté:

LogBefore.java

package com.zt.Aop;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component("Before")
public class LogBefore implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("-----before------" + method.getName() + "-----");
    }
}

LogAfter.java

package com.zt.Aop;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component("After")
public class LogAfter implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("-----after-----" + method.getName() + "------");
    }
}

Référence dans le fichier de configuration:

    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.zt.Service.*.*(..))"/>
        <aop:advisor advice-ref="Before" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="After" pointcut-ref="pointcut"/>
    </aop:config>

 

 

Je suppose que tu aimes

Origine blog.csdn.net/qq_39304630/article/details/112392223
conseillé
Classement