¿Por qué la anotación @ConditionalOnClass() no informa un error porque el archivo de clase no está en la ruta?

prefacio

Hay una anotación @ConditionalOnClass() en Spring Boot, lo que significa que la clase de configuración surte efecto solo cuando el archivo de clase especificado está en classpath . Pero sabemos que si una clase no está en la ruta, en el momento de la compilación, la clase con esta anotación no podrá compilarse.

Supongamos que existe tal pieza de código:

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

}

Si se va a compilar este código, al menos al escribir este código, debe haber un archivo SomeService.java en el classpath.

tiempo de compilación

Por ejemplo el siguiente código:

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

Se hace referencia a la clase Stu en este archivo, pero solo hay el archivo Test.java en la ruta y no hay Stu.java:

Luego, ejecutar javacel comando arrojará el siguiente error:

Por lo tanto, se puede deducir que esas clases de configuración que usan @ConditionalOnClass() deben tener los archivos de clase especificados por él en el momento de la compilación, pero esas clases se eliminan después de empaquetarlas en un paquete jar.

tiempo de ejecución

Pero aun así, cuando Spring Boot se está ejecutando, si Spring Boot quiere obtener el valor en @ConditionalOnClass() a través de la reflexión, seguirá informando un error. Sabemos que cuando el código se ejecuta en un lugar donde debe estar la clase especificada cargado, si la clase nunca se ha cargado, entonces la JVM cargará esta clase primero, pero si el archivo .class de esta clase no se puede encontrar en el classpath, se informará un error .

Por ejemplo, al igual que el ejemplo de ahora, esta vez colocamos Stu.class en la ruta, luego de una compilación exitosa, eliminamos Stu.class, ejecutamos el archivo, el resultado es el siguiente:

Se encuentra que aunque el método en la clase Test test()usa la clase Stu, no reporta un error porque no se ejecuta en esta línea de código. A continuación, modifique ligeramente el código:

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

Esta vez main()llamamos al método test(), recompilamos y eliminamos el archivo Stu.class antes de ejecutar, el resultado es el siguiente:

Se encontró que el programa lanzó una excepción porque test()el archivo Stu.class no se pudo encontrar durante la operación.

El principio de @ConditionalOnClass()

En resumen, ¿cómo lee Spring Boot el objeto Class en la anotación @ConditionalOnClass() sin informar un error? Sabemos que para leer el valor de la anotación, la JVM primero debe cargar el objeto Class del valor en memoria. De hecho, el principio es que Spring Boot no obtiene el valor a través de la reflexión, sino que lee directamente el archivo binario de la clase marcada con la anotación para obtener el valor en él .

En realidad, estos están comentados en el código fuente de la anotación @ConditionalOnClass():

Esto significa que si el atributo de valor (el tipo es Class<?>) se usa para la asignación, entonces es seguro usar la anotación @ConditionalOnClass() en la clase @Configuration, porque Spring Boot pasará ASM (un marco de código de bytes de operación) para obtener el valor de Clase correspondiente.

Cuando @ConditionalOnClass() se usa junto con @Bean, el atributo de valor no se puede usar para la asignación y se debe usar el atributo de nombre (de tipo String) , probablemente porque Spring Boot no usará ASM para obtener el valor en este momento. Por supuesto, además de usar el atributo de nombre, también puede continuar usando el atributo de valor de acuerdo con el código proporcionado en el comentario, pero necesita crear una clase @Configuration adicional para aislar la condición @Conditional.

Supongo que te gusta

Origin blog.csdn.net/weixin_55658418/article/details/130036959
Recomendado
Clasificación