Deja de poner Class.forName

Si tu tutorial, curso o libro sobre JDBC dice que pongas Class.forName() para conectarte con un simple MariaDB, MySQL o PostgreSQL, posiblemente el curso que estés siguiendo esté un poco anticuado. En esta lección te explico por qué es muy probable que ya no lo necesites.

No quiero meter beef ni derramar sangre, pero si el tutorial, libro o apuntes que estás siguiendo para aprender JDBC te recomienda que pongas Class.forName() de tu driver al principio de tu programa, posiblemente estés siguiendo un material un poco anticuado.

¿Por qué se pone Class.forName al usar JDBC?

Ya te conté en la lección anterior que los drivers son los que permiten adaptar el JDBC neutro al modelo de conexión de cada base de datos.

Dentro de cada driver, hay una clase principal, generalmente la misma que implementa la interfaz Driver, que contiene las rutinas de inicialización que registran el driver en el sistema para que se pueda utilizar. Como no quiero que me creas sin más, aquí tienes varios ejemplos con enlaces a código real:

En todos estos casos, la llamada a registerDriver() es la que enseña a JDBC cuál es el driver. Estamos de acuerdo en que este paso es necesario, porque si no, Java no sabrá de la existencia del mismo y por lo tanto no sabrá cómo traducir llamadas de JDBC a esa base de datos.

Sin embargo, como puede que sepas si has trabajado alguna vez con static (y si no, por cierto, tengo una lección sobre el tema), el contenido de un bloque static no se ejecuta inmediatamente en el momento de iniciar la aplicación. Se ejecuta la primera vez que se referencia en memoria la clase. Es decir, si quieres que el bloque static se ejecute, tienes que mencionar alguna vez la clase en tu programa. Bien sea intentando usar un método estático, fabricando una instancia, referenciando la propia clase con metaprogramación...

Y esta es la razón por la que te piden algunos tutoriales que pongas un código como Class.forName("org.postgresql.Driver"). Este método estático sirve para obtener una referencia a un objeto de tipo Class<?> para la clase especificada en la cadena de caracteres. Esto es metaprogramación, porque realmente lo que devolvería Class.forName() es sólo la clase interna que te permite sacar datos de la clase: cómo se llama, qué métodos tiene... pero en este caso lo que importa es que por haber hecho esta llamada, ya se menciona a la propia clase org.postgresql.Driver, y provoca que se ejecute su bloque static.

¿Y por qué no es necesario poner este método?

Hace años que en Java, los drivers son capaces de registrarse ellos solitos. JDBC 4 es la primera versión de Java que introduce este sistema. Y JDBC 4 salió en 2006. Es tan antigua que si descargas el PDF del JSR-221, te encontrarás con el logo de Sun, porque se publicó antes de que les comprase Oracle.

Portada del JSR-221

A estas alturas, ha pasado suficiente tiempo como para que todos los drivers se hayan adaptado a este sistema de carga automática, por lo que si tu driver es compatible con JDBC 4, debería registrarse automáticamente sin que tengas que hacer nada.

¿Cómo pueden conseguir esto? Usan una API que se incorporó en Java 6 denominada service provider y que sirve para hacer carga automática de clases, facilitando la creación de programas Java que usen patrones como plugins. (Piensa en los mods de un videojuego, si te ayuda a verlo mejor.)

El uso de service provider da para otro curso aparte. Sin embargo, por resumir: con esta API puedes definir Service Providers o proveedores de servicio, que son clases que van a formar parte de otros JARs y que van a implementar un Service Provider Interface, o interfaz de proveedor de servicio. Esta interfaz generalmente se compone de métodos para interactuar con un servicio que forma parte del programa principal.

Para que un JAR pueda anunciar que incluye service providers, utiliza un archivo especial que se ubica en el directorio META-INF del JAR. De este modo, la máquina virtual de Java puede saber qué providers existen porque puede buscar esos archivos especiales en los distintos JARs que hay en el classpath. Y luego, Java dispone de un método al que se le puede entregar una interfaz SPI, y te devuelve instancias de cada SP que hay en los JARs externos.

Este es el sistema que usa JDBC 4. Dentro de un JAR moderno de JDBC, debería haber un archivo ubicado en META-INF/services/java.sql.Driver. Si lo ubicas, verás que dentro tiene al menos una línea de código con el nombre de la clase de tu driver que registra cosas. Por ejemplo, org.postgresql.Driver en el caso del JDBC PostgreSQL driver (por ejemplo, haz clic aquí para ver el de la versión 42.7.5).

java.sql.Driver es el SPI. Una de las primeras cosas que hace JDBC cuando se intenta utilizar, es llamar a la función ensureDriversInitialized (traducible como asegurarse que los drivers están cargados), la cual utiliza la API de service provider para buscar ocurrencias de java.sql.Driver, cargando automáticamente cada subclase que haya en un JAR aparte, y por lo tanto provocando que se invoque el bloque static de cada uno.

Entonces, ¿por qué se sigue poniendo Class.forName?

Por supuesto, no lo sé. No puedo saber por qué hay libros o tutoriales que continúan haciendo esto. Pero mis teorías son:

  1. Son cursos un poco más antiguos: dado que Java tiene muchos años a sus espaldas, es posible que el curso o los apuntes se hayan hecho pensando en Java 5. Java por lo general es un lenguaje resistente al tiempo, y seguramente continúe siendo válido lo que cuenta ese curso, pero no sabe que hay una nueva forma mejor de hacer las cosas.
  2. Superstición: un poco relacionado con lo anterior. Si toda la vida se ha hecho así, por lo que son cosas que se han asimilado y nadie se ha parado a pensar en si sigue siendo necesario. Simplemente lo ponemos por si acaso.
  3. Drivers especiales o desactualizados: es necesario que cada driver JDBC esté adaptado a JDBC 4 para hacer esto. Lo mismo el tutorial está escrito para una versión antigua de JDBC, o bien se trata de un driver especial para una base de datos muy nicho que todavía no se ha adaptado a JDBC 4. Quizá se trate de una base de datos legacy con un conector antiguo, o quizás sus desarrolladores están tan ocupados contando billetes por seguir vendiendo la misma base de datos desde hace 30 años que han tenido las manos demasiado ocupadas como para escribir código nuevo.

Sin embargo, si estás usando un driver que es compatible con JDBC 4, deberías probar a no poner esa línea. Es más, si tienes dudas, diría que también. Si detectas que no carga el driver automáticamente, puedes ponerlo. Pero habría que ir pensando en no poner por defecto esa línea si no te hace falta.

Lista de reproducción
  1. 1
    ¿Qué es JDBC?
    5 minutos
  2. 2
    Configurar un driver
    7 minutos
  3. 3
    Deja de poner Class.forName
    8 minutos
  4. 4
    Conectarse en JDBC
    10 minutos
  5. 5
    Cómo ejecutar consultas
    10 minutos
  6. 6
    PreparedStatement, ¿por qué usarlo?
    11 minutos
  7. 7
    Cómo insertar, modificar y borrar datos
    10 minutos
  8. 8
    Transacciones
    12 minutos
  9. 9
    Cursores avanzados
    11 minutos
  10. 10
    ResultSets concurrentes
    10 minutos
  11. 11
    DataSource: así se usa JDBC en la vida real
    14 minutos
  12. 12
    ¿Se sigue usando JDBC?
    10 minutos