Pourquoi l'annotation @ConditionalOnClass() ne signale-t-elle pas une erreur car le fichier de classe qu'il contient n'est pas dans le chemin

avant-propos

Il y a une annotation @ConditionalOnClass() dans Spring Boot, ce qui signifie que la classe de configuration ne prend effet que lorsque le fichier de classe spécifié se trouve dans le classpath . Mais nous savons que si une classe n'est pas sur le chemin, alors au moment de la compilation, la classe avec cette annotation ne pourra pas être compilée.

Supposons qu'il existe un tel morceau de code :

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SomeService.class)
public static class SomeServiceConfiguration {
    
    

}

Si ce code doit être compilé, au moins lors de l'écriture de ce code, il doit y avoir un fichier SomeService.java dans le classpath.

temps de compilation

Par exemple le code suivant :

public class Test{
    
    
    public static void main(String[] args) {
    
    
         System.out.println("hello!");  
    }
    public void test() {
    
    
         Object obj = Stu.class;
         return;
    }
}

La classe Stu est référencée dans ce fichier, mais il n'y a que le fichier Test.java dans le chemin, et il n'y a pas de Stu.java :

Ensuite, l'exécution javacde la commande générera l'erreur suivante :

On peut donc en déduire que les classes de configuration qui utilisent @ConditionalOnClass() doivent avoir les fichiers de classe spécifiés par celle-ci au moment de la compilation, mais ces classes sont supprimées après avoir été empaquetées dans un package jar.

Durée

Mais même ainsi, lorsque Spring Boot est en cours d'exécution, si Spring Boot veut obtenir la valeur dans @ConditionalOnClass () par réflexion, il signalera toujours une erreur.Nous savons que lorsque le code s'exécute à un endroit où la classe spécifiée doit être chargé, si la classe n'a jamais été chargée, alors la JVM chargera cette classe en premier, mais si le fichier .class de cette classe est introuvable dans le classpath, alors une erreur sera signalée .

Par exemple, tout comme l'exemple tout à l'heure, cette fois nous mettons Stu.class dans le chemin, après une compilation réussie, supprimons Stu.class, exécutons le fichier, la sortie est la suivante :

Il s'avère que bien que la méthode de la classe Test test()utilise la classe Stu, elle ne signale pas d'erreur car elle ne s'exécute pas sur cette ligne de code. Ensuite, modifiez légèrement le code :

public class Test{
    
    
    public static void main(String[] args) {
    
    
         System.out.println("hello!"); 
         new Test().test();
    }
    public void test() {
    
    
         Object obj = Stu.class;
         return;
    }
}

Cette fois, nous main()appelons la méthode test(), recompilons et supprimons le fichier Stu.class avant de l'exécuter, le résultat est le suivant :

Il a été constaté que le programme a généré une exception car test()le fichier Stu.class n'a pas pu être trouvé pendant l'opération.

Le principe de @ConditionalOnClass()

Pour résumer, comment Spring Boot lit-il l'objet Class dans l'annotation @ConditionalOnClass() sans signaler d'erreur ? Nous savons que pour lire la valeur de l'annotation, la JVM doit d'abord charger l'objet Class de la valeur en mémoire. En fait, le principe est que Spring Boot n'obtient pas la valeur par réflexion, mais lit directement le fichier binaire de la classe marqué de l'annotation pour en obtenir la valeur .

Celles-ci sont en fait commentées dans le code source de l'annotation @ConditionalOnClass() :

Cela signifie que si l'attribut de valeur (le type est Class<?>) est utilisé pour l'affectation, il est alors sûr d'utiliser l'annotation @ConditionalOnClass() sur la classe @Configuration, car Spring Boot passera ASM (un cadre de bytecode d'opération) pour obtenir la valeur Class correspondante.

Lorsque @ConditionalOnClass() est utilisé avec @Bean, l'attribut value ne peut pas être utilisé pour l'affectation et l'attribut name (de type String) doit être utilisé , probablement parce que Spring Boot n'utilisera pas ASM pour obtenir la valeur à ce moment. Bien sûr, en plus d'utiliser l'attribut name, vous pouvez également continuer à utiliser l'attribut value selon le code donné dans le commentaire, mais vous devez créer une classe @Configuration supplémentaire pour isoler la condition @Conditional.

Je suppose que tu aimes

Origine blog.csdn.net/weixin_55658418/article/details/130036959
conseillé
Classement