How does DriverManager gets the instance of jdbc driver class - java

Class.forName is used to instantiate the driver class.
Class.forName do not have an object, it simply instantiates the driver class instance.If that is the case , how will DriverManager class get the reference of the instantiated driver class ?

Class.forName("X") causes the class named X to be dynamically loaded,
basically a call to forName("X") causes the class named X to be initialized (i.e., JVM executes all its static block after class loading).
To answer your question JVM executes the static block and the driver registers itself with the DriverManager.
This process is very well explained in following link:
http://www.xyzws.com/Javafaq/what-does-classforname-method-do/17

See the javadoc for the Driver Interface.
It says,
When a Driver class is loaded, it should create an instance of itself
and register it with the DriverManager. This means that a user can
load and register a driver by calling
Class.forName("foo.bah.Driver")

from javadoc
When the method getConnection is called, the DriverManager will
attempt to locate a suitable driver from amongst those loaded at
initialization and those loaded explicitly using the same classloader
as the current applet or application.
drivers loaded at initialization:: DriverManager class will attempt to load the driver classes referenced in the "jdbc.drivers" system property
drivers loaded explicitly:: by Class.forName("driver.name");

Related

JDBC Driver implementation and class loading

Not a long time ago I was implementing JDBC driver. But before jumping into work I've studied some MySQL JDBC driver sources and found out that they contain two implementations of the java.sql.Driver interface: com.mysql.jdbc.Driver and com.mysql.jdbc.NonRegisteringDriver, where Driver also extends NonRegisteringDriver.
The Driver class only contains a static block that calls DriverManager.registerDriver() to register the class:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
While NonRegisteringDriver implements all the java.sql.Driver interface methods.
My first thought was, that by implementing a driver this way developers of MySQL driver are following java.sql.Driver guidlines that state the following:
It is strongly recommended that each Driver class should be small and standalone so that the Driver class can be loaded and queried without bringing in vast quantities of supporting code.
But if I understand Java classloading correctly, there is absolutely no point in having separate com.mysql.jdbc.Driver class, as its parent with all the realisation code will be loaded anyway before execution of the static block.
Am I missing something here?
No, actually without com.mysql.jdbc.Driver class present implementation of mysql JDBC driver will not satisfy java.sql.Driver agreement, which claims:
When a Driver class is loaded, it should create an instance of
itself and register it with the DriverManager. This means that a user can load and register a driver by calling
Class.forName("foo.bah.Driver")}
com.mysql.jdbc.NonRegisteringDriver class doesn't contain this part of creating self-instance and registering it.
Why did mysql developers decided to distinguish implementation itself from class which essentially registers its instance? Hard to say exactly, but it could be convenient in case if they will decide to provide several implementations in same package. Then class com.mysql.jdbc.Driver will extend default one.
UPDATE: Essenstially things are as I described above. There are at least 3 derived classes which extend com.mysql.jdbc.NonRegisteringDriver:
com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver
com.mysql.jdbc.NonRegisteringReplicationDriver
While com.mysql.jdbc.Driver is default implementation, others overrides some methods from base class. If NonRegisteringDriver would contain static block for creation its instance and registering it, it would be not possible to have exactly one needed mysql driver in memory with deriving classes.
But in general there is no strong reasons for that. For example org.postgresql.Driver implementation contains full implementation of java.sql.Driver in itself.

Why we call Class.forname("com.mysql.jdbc.Driver") even if mysql.jar is added in class path

Why we call Class.forname("com.mysql.jdbc.Driver") even if mysql.jar is added in class path .I think System ClassLoader should load this class as well if not then can any body describe how definition of Driver is written such that it is not loaded when classes in the class path are loaded?
It was used in old Java versions for DriverManager to know about available JDBC drivers. No need to use it now, especially when you explicitly give driver class name.
No need to call Class.forname("com.mysql.jdbc.Driver") from Java 7 which has JDBC 4.
You can read about this here: What is the actual use of Class.forName("oracle.jdbc.driver.OracleDriver") while connecting to a database? .. the driver could be different.. the concept remains the same.
old Java versions for DriverManager to know about available JDBC drivers no this is not needed.
A call to Class.forName("X") causes the class named X to be dynamically loaded (at runtime). A call to forName("X") causes the class named X to be initialized (i.e., JVM executes all its static block after class loading). Class.forName("X") returns the Class object associated with the "X" class. The returned Class object is not an instance of the "x" class itself.
Class.forName("X") loads the class if it not already loaded. The JVM keeps track of all the classes that have been previously loaded. This method uses the classloader of the class that invokes it. The "X" is the fully qualified name of the desired class.
JDBC Driver Is a Good Example
You may have experience working with JDBC Drivers. For example, the classloader attempts to load and link the Driver class in the "org.gjt.mm.mysql" package. If successful, the static initializer is called.
Class.forName("org.gjt.mm.mysql.Driver");
Connection con = DriverManager.getConnection(url,?myLogin", "myPassword");
See definition of Driver class where it register Driver and instatiate Driver class in a static block which is called when class is loaded into JVM
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
public Driver() throws SQLException {
// Required for Class.forName().newInstance()
}
}
If we write
Driver dr=new Driver();
Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/massiverun","root","admin");
System.out.println("Print"+con);
then class Driver will be instantiated twice and also static block will be called
when new Driver() is called .if we Use Class.forname("com.mysql.jdbc.Driver") in place of new Driver() Driver class is instantiated once and if class is already loaded into JVM static block is not called for second time.

Loading JDBC driver

I am told that the prefered method to load the JDBC driver is :
Class.forName(driverName);
I understand that this is better for a dynamic decision between multiple drivers maybe read from an XML config file or user input. The thing I am curious about is how does invoking this statement loads the stated driver into the environment where we are not even storing the resultant "Class" object anywhere. The JavaDocs entry says:
public static Class forName(String className)
throws ClassNotFoundExceptionReturns
returns the Class object associated with the class or interface with the given string name
In that case, how do the Java developers managed to facilitate the existence of driver object with merely this statement?
The Class#forName() runs the static initializers (you know, static applies to the class, not to the instance). The JDBC driver implementation should register itself in the static initializer.
public class SomeDriver implements Driver {
static {
DriverManager.registerDriver(new SomeDriver());
}
}
Note that there exist buggy JDBC drivers such as org.gjt.mm.mysql.Driver which incorrectly registers itself inside the constructor instead. That's why you need a newInstance() call afterwards on such drivers to get them to register themselves.

How does Class.forName() work?

I just learned about java.sql package. It uses Class.forName() to dynamically load the driver which extends DriverManager.
Then we get connection using DriverManager.getConnection() method.
So how does the entire thing work?
How does DriverManager class know how to get the connection without using class name of the actual driver.
Also can we use Class.forName() for custom applications... if this is explained with an example I will be very happy.
Class.forName simply loads a class, including running its static initializers, like this:
class Foo {
static {
System.out.println("Foo initializing");
}
}
public class Test {
public static void main(String [] args) throws Exception {
Class.forName("Foo");
}
}
All the rest of the procedure you're talking about is JDBC-specific. The driver - which implements Driver, it doesn't extend DriverManager - simply registers an appropriate instance using DriverManager.registerDriver. Then when DriverManager needs to find a driver for a particular connection string, it calls connect on each registered driver in turn until one succeeds and returns a non-null connection.
Note that this way of registering drivers is reasonably old-fashioned - look at the docs for DriverManager for more modern ways of getting at a data source.
When we create an instace of a class using new operator, it does two things
Load the class in to memory, if it is not loaded -
which means creating in-memory representation of the class from the .class file so that an instance can be created out of it. This includes initializing static variables (resolving of that class)
create an instance of that class and store the reference to the variable.
Class.forName does only the first thing.
It loads the class in to memory and return that reference as an instance of Class. If we want to create an instance then, we can call newInstance method of that class. which will invoke the default constructor (no argument constructor).
Note that if the default constructor is not accessible, then newInstance method will throw an IllegalAccessException. and if the class is an abstract class or interface or it does not have a default constructor, then it will throw an InstantiationException. If any exception araises during resolving of that class, it will throw an ExceptionInInitializerError.
If the default constructor is not defined, then we have to invoke the defiend constructor using reflection API.
But the main advantage with Class.forName is, it can accept the class name as a String argument. So we can pass the class name dynamically. But if we create an instance of a class using new operator, the class name can't be changed dynamically.
Class.forName() inturn will call loadClass method of the caller ClassLoader (ClassLoder of the class from where Class.forName is invoked).
By default, the Class.forName() resolve that class. which means, initialize all static variables inside that class.
same can be changed using the overloaded method of Class.forName(String name,boolean initialize,ClassLoader loader)
The main reason for loading jdbc driver using Class.forName() is, the driver can change dynamically.
in the static block all Drivers will create an instance of itself and register that class with DriverManager using DriverManager.registerDriver() method. Since the Class.forName(String className) by default resolve the class, it will initialize the static initializer.
So when we call Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver"),
the Driver class will be loaded, instanciated and registers with DriverManager
So if you are using new Operator you have to do the following things.
Code:
Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver();
DriverManager.registerDriver(drv);
Class.forName(..) loads and initializes the target class. This in turn means that the static initializer blocks are invoked (code defined in static { .. }.
If you look at, for example, MySQL's driver, in that static block the driver is registering itself: DriverManager.registerDriver(new Driver());
You can omit the Class.forName(..) and register the driver yourself if you can "afford" the compile-time dependency on MySQL's driver.
That said, it will rarely be relevant to use Class.forName(..) to initialize classes from your application, because compile-time dependency is not an issue there.
Also note that Class.forName(..) is no longer required for JDBC since version 4. By using the service provider mechanism you can instruct the driver manager what to load by a system property.
The reason why Class.forName() is frequently mentioned in SQL examples, is because there was no magic to tell the JDBC DriverManager how to map the JDBC URL provided to a real driver.
E.g. "mysql" should map to a given MySQL class, "thin" maps to the Oracle class, "as400" maps to the DB2/400 class.
By explicitly loading the class, this allowed the code within the class registering itself with the DriverManager to be run.
These days the magic hooks are present allowing the JVM to autodiscover the drivers (if new enough) so the call is superfluous, but out of habit many still use it.

In Java, connecting to mysql, what is the meaning of Class.forName?

What is the purpose of this line?
It does not return a value or set the state of an existing class/object (or is it?)
Class.forName ("com.mysql.jdbc.Driver").newInstance ();
It uses reflection to look on the classpath for a class called "com.mysql.jdbc.Driver" and makes a new instance of it.
In your code when you write
Integer foo = new Integer()
You could instead write
Integer foo = Class.forName("java.lang.Integer").newInstance()
But why go to all this trouble? Because you want to load your database driver at runtime, not hard code it in. So if you change databases, you just changes a config file that would load a different database driver. In your specific case it may not matter, but it does open up new possibilities on database configuration (and this Class.forName jazz is how it is usually done)
Almost certainly, com.mysql.jdbc.Driver has a static initializer that looks like this:
static {java.sql.DriverManager.registerDriver(new com.mysql.jdbc.Driver())};
This static initializer is called when you use the forName method. So without realizing it you registered the MySQL driver.
As for the newInstance, I don't know why it is there. It seems unnecessary.
It loads the MySQL JDBC driver.
The reason you do this is you don't directly use this class so there is no static binding to the class name. When you attempt to open a database connection you simply use a java.sql.Connection and not a MySQL specific class or interface. That translation is done behind the scenes with dynamic class loading.
You're loading that class so it can register itself with the JDBC subsystem for when you make the connection subsequently.
Its purpose it's to dynamically load the class definition specified by the fully qualified name passed as string argument.
This means that the JVM will effectively search for the .class file inside classpath items and then with newInstance() you ask for a new instance of that class.
If the class had already been loaded before then it's already in cache and will not be retrieved from the file again. (not 100% sure about it, maybe you are allowed to "update" a class definition at runtime but personally I think it would create inconsistencies)
Calling Class.forName creates an instance of your driver.
A call to Class.forName("X") causes the class named X to be dynamically loaded (at runtime).
When you run java program, you have classpath and default location to pick up some jars (contain classes) and classes. The JVM will load all those jars (contain classes) and classes to prepare starting your java program.
Class.forName("className") look into all this loaded classes to return the particular "className" for you to create an instance/object from it.
It is a dynamic way of doing the same as in compile time object instantiation:
ClassName classInstance = new ClassName();
Class.forName is used to load the Class object for the specified full class name. When the object, here refers to com.mysql.jdbc.Driver, is loaded, the static expression will be called. So although Class.newInstance() is not invoked to create a new instance, there must be some static initialization in com.mysql.jdbc.Driver.
Class.forName(String name)
Returns the Class object associated with the class [...] the given string name
That means, that, it would return ( or attempt ) to return the class com.mysql.jdbc.Driver
Later Class.newInstace()
Creates a new instance of the class represented by this [...] object
So, what that line does, is to create dynamically a mysql Driver instance.
This:
Class.forName ("com.mysql.jdbc.Driver").newInstance ();
Would be equivalent to:
import java.sql.Driver;
....
Driver driver = new com.mysql.jdbc.Driver()
By the way according to DriverManager doc, you don't have to use it anymore:
Applications no longer need to explictly load JDBC drivers using Class.forName()
It use to be needed to load the driver, but now the DriverManager uses other strategy.
Finally, read the:
NOTE: The DataSource interface, new in the JDBC 2.0 API, provides another way to connect to a data source. The use of a DataSource object is the preferred means of connecting to a data source.

Categories

Resources