[SSM-Spring Chapitre 04] Proxy de programmation orienté aspect AOP mode-proxy dynamique jdbc-proxy dynamique CGLIB

Concept AOP

  AOP adopte un mécanisme d'extraction horizontal, qui consiste à extraire le code répété dispersé dans chaque méthode, puis à appliquer le code extrait à l'endroit où il doit être exécuté (généralement utilisé pour la journalisation, les statistiques de performance, la sécurité Contrôle, traitement des transactions, gestion des exceptions, etc.)

Terminologie AOP

  1. Aspects
      (Aspect) fait référence à l'encapsulation de la classe transversale aux fonctions système (telles que le traitement des transactions).
  2. Le point de connexion
      (Joinpoint) fait référence à certains points du programme en cours d'exécution, tels que les appels de méthode ou les exceptions.
  3. Pointcuts pointcut
      (Pointcut) sont les points de connexion nécessitant un traitement. Dans Spring AOP, toutes les exécutions de méthode sont des points de connexion, et le point d'entrée est une information de description, qui modifie le point de connexion, et le point d'entrée est utilisé pour déterminer quels points de connexion doivent être traités.
  4. La notification (traitement amélioré)
      est un morceau de code ajouté de l'aspect à un point de connexion spécifique (satisfaisant la règle de coupe de point), c'est-à-dire le code de programme à exécuter au point de coupe défini. Il peut être compris comme la méthode de découpe de la surface après ouverture de la surface. Par conséquent, la notification est une réalisation concrète de l'aspect.
  5. Introduction
      (Introduction) permet d'ajouter des méthodes et des attributs personnalisés aux classes d'implémentation existantes.
  6. Audience
      Audience (objet cible) fait référence à tous les objets à notifier. Si l'infrastructure AOP utilise un proxy d'exécution (AOP dynamique) pour implémenter des aspects, l'objet de notification est toujours un objet proxy.
  7. Agissant
      après que le proxy (Proxy) est une notification à l'objet cible, l'objet est créé dynamiquement.
  8. Le groupe dans le
      groupe dans (Tissage) est inséré dans la section de code sur l'objet cible, le processus pour générer l'objet proxy. Selon différentes technologies d'implémentation, il existe trois méthodes de tissage AOP: le tissage du compilateur nécessite un compilateur Java spécial; le tissage de la période de chargement de classe nécessite un chargeur de classe spécial; le tissage proxy dynamique, qui est ciblé au moment de l'exécution Ajoutez une notification à la classe pour générer des sous-classes. Le framework Spring AOP utilise le tissage proxy dynamique par défaut, tandis qu'AspectJ (un framework AOP basé sur Java) utilise le tissage du compilateur et le tissage de la période de chargement de classe.



Modèle d'agence (tout comme l'existence d'un intermédiaire)

La classe proxy est responsable du prétraitement des messages pour la classe déléguée, du filtrage et du transfert des messages, et du traitement ultérieur une fois le message exécuté par la classe déléguée. (Ajouter des fonctionnalités supplémentaires)

Proxy (virtuel)

  Les agents virtuels sont représentatifs des objets coûteux à créer . Les agents virtuels ne créent souvent pas d'objet tant que nous n'en avons pas vraiment besoin. Lorsque l'objet est créé avant et lors de sa création, l'agent virtuel agit comme un substitut de l'objet. Une fois l'objet créé, le proxy délègue la demande directement à l'objet.
Insérez la description de l'image ici



Proxy statique

  Vous devez implémenter explicitement la même interface que la classe d'objet cible (RealSubject) , et la classe proxy a été créée avant l'exécution du programme .

Réalisation de cas

  1. Créer l'interface et l'implémentation de la classe proxy
public interface Math {
    
    
    public int jia(int a, int b);//加
    public int jian(int a, int b);//减
}
public class MathImpl implements Math{
    
    

    public int jia(int a,int b){
    
    
        return a+b;
    }
    public int jian(int a,int b){
    
    
        return a-b;
    }
}
  1. Créer des classes d'outils pour implémenter des méthodes courantes
public class Tools {
    
    

    public void check(){
    
    
        System.out.println("权限检查......");
    }
    public void log(){
    
    
        System.out.println("日志记录......");
    }

}

  1. Créer une classe proxy
public class MathProxy implements Math {
    
    

//    MathImpl mathImpl = new MathImpl();  //业务逻辑
//    Tools tools = new Tools();  //工具类
    MathImpl mathImpl;  //业务逻辑
    Tools tools;  //工具类

//    public MathProxy(){}
    public MathProxy(MathImpl mathImpl, Tools tools) {
    
    
    	//在构造器中直接初始化了
        this.mathImpl = mathImpl;
        this.tools = tools;
    }

    @Override
    public int jia(int a, int b) {
    
    
        tools.check();
        int result = mathImpl.jia(a,b);
        tools.log();
        return result;
    }

    @Override
    public int jian(int a, int b) {
    
    
        tools.check();
        tools.log();
        return mathImpl.jian(a,b);
    }
}
  1. Créer une classe de test
public class Test {
    
    

    public static void main(String[] args) {
    
    
        /* 被代理对象--业务类 数学计算类 */
        MathImpl mathImpl = new MathImpl();
		//创建工具类
        Tools tools = new Tools();
        
//      代理对象
        Math math = new MathProxy(mathImpl,tools);
        int result1 = math.jia(2,6);
        System.out.println(result1);
        
        int result2 = math.jia(3,2);
		System.out.println(result2);
    }
}

  1. résultat de l'opération

Insérez la description de l'image ici



Proxy dynamique (les proxy dynamiques JDK et CGLIB sont couramment utilisés dans Spring AOP - utilisent désormais généralement aspectj)

  Il n'est pas nécessaire d'implémenter explicitement la même interface que la classe d'objet cible (RealSubject), mais reporter cette implémentation jusqu'à ce que le programme soit exécuté par la JVM. Les agents dynamiques sont créés en cas de besoin, pas à l'avance .

La principale différence entre le proxy dynamique JDK et CGLIB:

Le proxy dynamique JDK ne peut proxy que les méthodes d'interface de la classe qui implémente l'interface.
Le proxy dynamique CGLIB implémente le proxy basé sur l'héritage, il ne peut donc pas proxy des classes finales, des méthodes privées et des méthodes statiques.

La stratégie par défaut utilisée par le proxy dans Spring AOP est:

Si l'objet cible implémente l'interface, le proxy dynamique JDK est utilisé par défaut.
Si l'objet cible n'implémente pas l'interface, CgLib est utilisé pour le proxy dynamique.
Si l'objet cible implémente l'interface et que CgLib est forcé de créer un proxy, CgLib est utilisé pour le proxy dynamique.


1. Le proxy dynamique JDK implémente Spring AOP

  Le proxy dynamique JDK est la méthode fournie par le package java.lang.reflect. *. Il doit utiliser une interface pour générer des objets proxy. Par conséquent, pour les classes qui utilisent des interfaces métier, Spring utilise le proxy dynamique JDK pour implémenter AOP par défaut .
  Dans Spring, le proxy dynamique JDK est utilisé par défaut pour implémenter la programmation AOP . L'utilisation de org.springframework.aop.framework.ProxyFactoryBean pour créer un proxy est le moyen le plus simple d'implémenter Spring AOP.

Réalisation de cas

  1. Créer l'interface et la classe d'implémentation de la classe proxy
public interface UserDao {
    
    
    public void save(String name);  //保存
    public void delete();           //删除
}
//被代理类
public class UserDaoImpl implements UserDao{
    
    
    @Override
    public void save(String name) {
    
    
        System.out.println("保存用户成功 :"+name);
    }

    @Override
    public void delete() {
    
    
        System.out.println("删除用户成功:");
    }
}
  1. Créer une classe d'aspect (méthode publique)
//切面类:定义公共方法
public class MyAspect {
    
    
    public void check(){
    
    
        System.out.println("check user......正在查找用户");
    }

    public void log(){
    
    
        System.out.println("logging.....正在记录日志");
    }
}
  1. Créer une classe proxy
//代理类
public class MyProxy implements InvocationHandler {
    
    

    private UserDao userDao;    //被代理类
    private MyAspect myAspect;  //切面类 -- 定义公共方法

    public MyProxy(UserDao userDao, MyAspect myAspect) {
    
    
        this.userDao = userDao;
        this.myAspect = myAspect;
    }

    //创建代理对象
    public Object create(){
    
    
        ClassLoader classLoader = userDao.getClass().getClassLoader();
//      Class<?>[] interfaces  被代理对象的实现接口
        Class<?>[] interfaces = userDao.getClass().getInterfaces();
        UserDao proxy = (UserDao) Proxy.newProxyInstance(classLoader,interfaces,this);
        System.out.println("创建代理对象create");
        return proxy;
    }

//    调用方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
//        织入 advice 加入到 被代理对象方法之前或之后
//        method就是调用的被代理对象的方法
        String methodName = method.getName();
//        Object 被代理对象
//        调用方法
        System.out.println("调用invoke方法");
        myAspect.check();//调用切面方法
        method.invoke(userDao,args);//userDaoImpl.save(参数)
        myAspect.log();//调用切面方法
        return null;
    }
}
  1. Créer une classe de test
public class Test {
    
    
    public static void main(String[] args) {
    
    
//      被代理类
        UserDao userDao = new UserDaoImpl();
//      切面
        MyAspect myAspect = new MyAspect();

        //创建代理类  参1:被代理类  参2:切面(公共方法)
        MyProxy myProxy = new MyProxy(userDao,myAspect);
        //通过代理类来创建实例 - 代理对象
        UserDao proxy = (UserDao)myProxy.create();
        proxy.save("GF_浪夏一学");
        proxy.delete();
    }
}
  1. résultat de l'opération

Insérez la description de l'image ici


2. Le proxy dynamique CGLIB implémente Spring AOP

  CGLIB (Code Generation Library) est un package de génération de code open source hautes performances qui utilise la technologie bytecode de très bas niveau pour générer une sous-classe de la classe cible spécifiée et améliorer la sous-classe. Le package JAR requis par CGLIB a été intégré dans le package Spring Core, et il n'est pas nécessaire d'importer le package JAR séparément

Réalisation de cas

  1. Créer une classe proxy (classe cible)
public class UserService {
    
    
    public void save(){
    
    
        System.out.println("save service ......");
    }
    public void delete(){
    
    
        System.out.println("delete service ......");
    }
}
  1. Créer une classe d'aspect (méthode publique)
public class MyAspect {
    
    

    public void check(){
    
    
        System.out.println("check方法......检查包");
    }

    public void log(){
    
    
        System.out.println("logging方法......记录日志");
    }
}
  1. Créer une classe proxy
public class MyProxy<T> implements MethodInterceptor {
    
    

    private T byProxy;          //被代理类
    private MyAspect myAspect;  //切面

    public MyProxy(T byProxy, MyAspect myAspect) {
    
    
        this.byProxy = byProxy;
        this.myAspect = myAspect;
    }

//    创建代理对象
    public T create(){
    
    
        // 通国Enhancer创建代理类 ----  Proxy
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(byProxy.getClass());
        enhancer.setCallback(this);//实现MethodInterceptor接口的对象,就是当前对象
        T proxy = (T)enhancer.create();
        return proxy;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    

//        Method method,调用的被代理对象方法
        String methodName = method.getName();
        if(methodName.equals("save")){
    
    
            myAspect.check();
            method.invoke(byProxy,objects);
            myAspect.log();
        }
        if(methodName.equals("delete")){
    
    
            myAspect.check();
            method.invoke(byProxy,objects);
            myAspect.log();
        }
        return null;
    }
}

  1. Créer une classe de test
public class CGLIBTest {
    
    
    public static void main(String[] args) {
    
    
//       被代理对象
        UserService userService = new UserService();
        MyAspect myAspect = new MyAspect();

        //创建代理对象
        MyProxy myProxy = new MyProxy(userService,myAspect);
        //通过代理类创建被代理对象
        UserService service = (UserService)myProxy.create();

        //调用方法
        service.save();
        service.delete();
    }
}
  1. résultat de l'opération
    Insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/qq_40542534/article/details/108683231
conseillé
Classement