Adventures in JDBC and the PostgreSQL JDBC driver: Part 7 - The JDBC driver loading process in Wildfly

In the previous article, we have learned how to add a JDBC database driver module into Wildfly, and how to configure a datasource to use hte driver. In this article, let’s see the JDBC driver loading process in Wildfly.

In Wildfly source code (See https://github.com/wildfly/wildfly), the connector module contains the datasources subsystem. Here is the screenshot of the source code structure of wildfly:

/assets/jdbc/datasources.png

The above screenshot shows the datasources subsystem. In the subsystem, we can find the org.jboss.as.connector.subsystems.datasources.JdbcDriverAdd class, and here is its class diagram:

/assets/jdbc/JdbcDriverAdd.png

The above diagram shows the methods in JdbcDriverAdd class. Firstly we need to check the performRuntime(...) method. Here is the sequence diagram of the method:

/assets/jdbc/org.jboss.as.connector.subsystems.datasources.JdbcDriverAdd.performRuntime(OperationContext, ModelNode, ModelNode).png

From the above diagram, we can find out two things: Firstly the method will try to fetch multiple values defined by the users. For example, there are DRIVER_CLASS_NAME and DRIVER_XA_DATASOURCE_CLASS_NAME that users can set in the server configuration file.

Another thing we can see from the above diagram is that the method will try to find the JDBC driver class automatically if driverClass is null, and it will invoke the loadService(Driver.class) method for this task.

Let check the above notes one by one. First let’s see the origin class of the DRIVER_CLASS_NAME and DRIVER_XA_DATASOURCE_CLASS_NAME constants. They are defined in the org.jboss.as.connector.subsystems.datasources.Constants class, and here is its class diagram:

/assets/jdbc/Constants.png

The above diagram just show part of the whole class because it is too big. You can check the code directly to get all the constants defined in the class. These constants can mostly be defined in the server configuration file. For example, we can see the string value of DATASOURCE_DRIVER_CLASS_NAME is driver-class. Actually we can configure this in the standalone/configuration/standalone.xml:

<driver name="postgresql" module="org.postgresql">
	<driver-class>org.postgresql.Driver</driver-class>
</driver>				

But in the last article, we didn’t configure the driver-class, but Wildfly can still load the driver class correctly. This is because the loadService(...) method will help us to find the driver class in the module. Here is the relative code in the method:

 if (driverClassName == null) {
            final ServiceLoader<Driver> serviceLoader = module.loadService(Driver.class);
            boolean driverLoaded = false;
            if (serviceLoader != null) {
                for (Driver driver : serviceLoader) {
                    startDriverServices(target, moduleId, driver, driverName, majorVersion, minorVersion, dataSourceClassName, xaDataSourceClassName);
                    driverLoaded = true;
                    //just consider first definition and create service for this. User can use different implementation only
                    // w/ explicit declaration of driver-class attribute
                    break;
                }
            }
...

From the above code, we can see the module.loadService(Driver.class) method will try to find the class that implements the Driver.class interface from the module. If it finds the driver classes, it will install them one by one by using the startDriverServices(...) method.

To verify our analysis, we can set a breakpoint in JdbcDriverAdd class. To understand how to debug the Wildfly startup process, you need to read these two articles firstly:

I have introduced the techniques to debug the Wildfly server. I used the methods introduced in above articles to catch the startup process by setting the breakpoint in JdbcDriverAdd class, and then start the Wildfly server in debug mode. Here is what I get in my IntelliJ IDEA environment:

/assets/jdbc/JdbcDriverAdd-debug.png

The above screenshot shows that during the Wildfly server startup process, it will use the JdbcDriverAdd to load the drivers defined in configuration file. Because we didn’t define the driver-class in standalone.xml, so it goes into the logic to find the driver class automatically.

Now I step the code to the startDriverServices(...) method, and here is the screenshot:

/assets/jdbc/JdbcDriverAdd-debug2.png

From the above screenshot, we can see Wildfly has found the PostgreSQL JDBC driver, which is org.postgresql.Driver.

Now let’s go a little big deeper into the startDriverServices(...) method. I stepped into the method and here is the screenshot:

/assets/jdbc/JdbcDriverAdd-debug3.png

From the above screenshot, we can see that Wildfly will create a DriverService for the driver and install it into its micro container. I won’t dive into deeper details in this article, but you may want to learn about the micro container design of Wildfly. If so, you can read these articles:

The above articles will give you an introduction to the Wildfly micro container design.

In this article, we have checked how does Wildfly load the JDBC driver. In next article, I will introduce the Wildfly datasource loading process.