What is the actual use of Class.forName("oracle.jdbc.driver.OracleDriver") while connecting to a database? Why cant we just import the same class, instead why we are loading it.
The basic idea behind using Class.forName() is to load a JDBC driver implementation. A (normal) JDBC driver must contain a static initializer that registers an instance of the driver implementation with java.sql.DriverManager:
JDBC drivers must implement the Driver interface, and the implementation must contain a static initializer that will be called when the driver is loaded. This initializer registers a new instance of itself with the DriverManager
(from JDBC 4.1, section 9.2)
Since JDBC 4.0 however there is a new way to register drivers: the jar of a JDBC driver needs to include a file /META-INF/services/java.sql.Driver which contains the name(s) of the java.sql.Driver implementations in that jar. When you create a connection using the DriverManager, it will use java.util.ServiceLoader to enumerate all /META-INF/services/java.sql.Driver files in the classpath and load all drivers so they get registered.
The DriverManager.getConnection method has been enhanced to support the Java Standard Edition Service Provider mechanism. JDBC 4.0 Drivers must include the file META-INF/services/java.sql.Driver. This file contains the name of the JDBC driver’s implementation of java.sql.Driver.
(from JDBC 4.1, section 9.2.1)
The reasons drivers are loaded this way, is that it allows you to decouple an application from the driver (and database) it uses. This means that you can write, compile and even distribute an application without any drivers, you only need to use the interfaces provided in the java.sql (and javax.sql) package - which is part of Java - without needing to access the implementation directly.
The user of the application then adds a valid JDBC driver to the classpath (and configuring things like a connection string) so the application can actually to connect to a database. Before JDBC 4.0, the user would have to specify the driver name so that the application could load it using Class.forName, with a JDBC 4.0 compliant driver and Java 6 or higher this discovery is automatic.
When you load a driver literally with Class.forName("oracle.jdbc.driver.OracleDriver") it might feel like overkill, but if you keep in mind that it could also be a string pulled from a config file (or from user input) you might start to understand why it is so powerful.
Of course this driver independence is not 100%, especially not if your application uses vendor specific SQL. But the theory is that your application can be database independent. JDBC also provides some additional mechanisms to address this, eg JDBC escapes to provide a common syntax that the driver translates to the specific syntax, and DatabaseMetaData which allows you to discover features, reserved words etc which allow you to create or generate compatible queries.
A couple reasons to use Class.forName("") instead of just referencing the class directly:
Using Class.forName("") gives you more obvious control over where exactly the first attempt to load the specified class will be made in your code. This makes it more obvious where the code will fail (throw an exception) if that class is not present in the classpath when that code runs.
If you simply import the class and then reference it in your code, it becomes slightly less obvious where the code will throw an exception if the class is not present.
Also, using Class.forName("") is a way to get around potential compile-time restrictions. If, for example, the person compiling the code does not (for, let's say, licensing or intellectual property reasons) have access to the class oracle.jdbc.driver.OracleDriver, they may find it easier to compile code which references the class by Class.forName("") rather than directly.
If you do not need to use any methods, fields, or inner classes of the specified class, then Class.forName("") may be the clearest way to express that the only thing desired is to load the class (and have its static initializers run), and nothing else.
I don't think Class.forName exhibits any different functional behavior than referencing the class directly. It uses the calling class' classloader by default, which should be the same classloader that is used when referencing the class directly. There are some overloads to Class.forName("") that let you customize the class loading behavior a bit more.
It`s a legacy way to do so. Importing class you will have extra dependency
From The Java Tutorial:
In previous versions of JDBC, to obtain a connection, you first had to
initialize your JDBC driver by calling the method Class.forName. This
methods required an object of type java.sql.Driver. Each JDBC driver
contains one or more classes that implements the interface
java.sql.Driver.
...
Any JDBC 4.0 drivers that are found in your class
path are automatically loaded. (However, you must manually load any
drivers prior to JDBC 4.0 with the method Class.forName.)
Sometimes it is required to load a class during the run time. i.e, any class can be loaded into the memory location dynamically while executing the java application. The Class.forName is used to load any given class (within double quotes as String) at run time. For example, when we use IDE, we see there will be a GUI builder which allows us to drag and drop the buttons, text fields, etc. This drag and drop mechanism internally requires certain classes to be loaded at run time.
In the Class.forName (sun.jdbc.odbc.JdbcOdbcDriver), the Class belongs to the package java.lang.Class and the forName() is a static method of the java.lang.Class. The JDBC Drivers (String) will be loaded into the class dynamically at run time and forName method contains static block which creates the Driver class object and register with the DriverManager Service automatically. Since the forName() is static, we call it using the class name (Class).
When we want to execute static block of a class, without creating its object then we can use class.forName(). Most of the work that Driver class do, exists in its static block.
Now what we require in our JDBC connectivity is to get the driver registered with DriverManager and to obtain connections with it, so this can be achieved simply by getting static block executed and there is no requirement to create object of that class. This approach will give a better performance.
Related
Is it correct that when we dynamically load a .class class file, we need to use reflection to access the methods defined in the class?
When we use a JDBC driver in our Java program,
if I am correct, the JDBC driver is also dynamically loaded behind the scene.
But we never need to use reflection to access the methods defined in the JDBC driver. Instead we import java.sql and access the classes and methods defined in the java.sql.
Under the hood, is there reflection undergoing? If not, how does it work without reflection?
In general, when we dynamically load a .java class file, how can we eliminate or hide the use of reflection to access the methods defined in the class, just like a JDBC driver?
By the way, does a JDBC driver define exactly a class?
Thanks.
JDBC driver needs to implement java.sql.Driver interface (e.g. oracle.jdbc.OracleDriver). Apart from that the JDBC driver code is just plain Java code. It can use reflection or any other Java language feature. It's up to the driver vendor to decide if it's worth it e.g. using classes introduced in Java 8 will make it compatible only with Java 8+.
What is and isn't dynamically loaded depends on the JVM and the implementation of ClassLoader. Certain technologies like OSGI give more flexibility by implementing a ClassLoader that allows for unloading parts of the application.
Loading the JDBC driver class should happen so infrequently, and be cached by JVM, that cost of this one reflective call to load the driver should be negligible. A single SELECT 1 query will be orders of magnitude more expensive than loading the driver bytecode.
Starting with JDBC 4.0 it is no longer necessary to do any reflection-related calls to work with JDBC drivers, as any driver discovered on your class path is loaded automatically.
If your code must support pre-JDBC 4 code, or if your JDBC driver is not located on your class path, you must call Class.forName to load the driver.
Under the hood, is there reflection undergoing?
JDBC 4.0 uses Service Provider mechanism to locate JDBC drivers without doing reflection directly. At some point, however, JDBC driver class needs to be loaded, so a reflection call must be performed.
We have a java library (more like a framework) which can be used to build JDBC drivers. The framework implements the JDBC interface, and you implement some interfaces which are consumed by the framework to realize the driver.
One issue which has come up is that if you create two drivers with this framework, and try to use them simultaneously in a single JVM, only a single set of the framework classes will be loaded.
This is bad for at least two reasons:
The framework contains singletons, so only the first driver loaded
actually works correctly.
Even if we removed all singletons, things
could break if the 'wrong version' of the framework is loaded at
runtime for one of the drivers.
The solution used was to rename the framework class packages for each driver, so that they would no longer conflict. While this works, there is a concern about the bytecode manipulation, as it happens after our testing.
My question: Is there a better way? This needs to be handled from our side, not the application's, as an application uses the driver simply as a JDBC driver, so it needs to be transparent.
One idea I had was to serialize all the classes of the driver (other than the 'entrypoint' classes which implement Driver/DataSource) into some sort of resource which is packaged in the driver jar (with the FQN of the resource and entrypoint classes being unique to the driver), then have the entrypoint classes, in a static initialization block, read out the classes and load them with a private classloader. Are there any glaring problems I'm missing with this approach?
As for JDBC4 it is required that the JDBC driver loads automatically. It is made by adding a static block where the driver registers in DriverManager. However when I'm writing such a block in my class, it is executed only when I create the object of this class. Otherwise the code is not run.
My question is: how do the drivers initilize itself, when they are not being created from the application code, however they are registered in DriverManager when I use it for getting db connection?
The paragraph 9.2 of the JDBC4 specification, states that the Driver implementation must register itself to the DriverManager upon class loading, so that when the Driver implementation is loaded the static initializer will automatically
register an instance of the driver.
So, simply loading the Driver implementation by (Class.forName("driverClassName")), will register the driver with the DriverManager.
Alternatively, the specification provides a mean to externally specify the drivers to be loaded (and thus registered) by the DriverManager, through the system property jdbc.drivers (see paragraph 9.2.1):
java -Djdbc.drivers=com.acme.jdbc.AcmeJdbcDriver Test
These methods of registration are available also in old JDBC3 implementations.
JDBC4 introdces a new method of registration, leveraging the Service Provider Mechanism:
every compliant driver must provide a jar including the META-INF/services/java.sql.Driver file.
The DriverManager (on DriverManager.getConnection() calls ) uses the java.sql.Driver service provider and loads the classes there specified, thus automatically registering the driver. This removes the need to invoke Class.forName (see paragraph 9.2.1 and paragraph 3.1, first bullet).
You can use the ServiceLoader facility of Java to automatically load services.
You need to put a file in the JAR that lists your class, then Java will automatically load it when the service is needed. Check the documentation for ServiceLoader for more details.
The answer to this similar question actually says that this is the way that JDBC uses.
In previous versions of JDBC when using a DataSource you will often see a call to Class.forName("driver.class")
In previous versions of JDBC, to obtain a connection, you first had to
initialize your JDBC driver by calling the method Class.forName. This
methods required an object of type java.sql.Driver. Each JDBC driver
contains one or more classes that implements the interface
java.sql.Driver.
The documentation further states:
Any JDBC 4.0 drivers that are found in your class path are
automatically loaded. (However, you must manually load any drivers
prior to JDBC 4.0 with the method Class.forName.)
So I assume the classpath is being scanned for any classes implementing the driver interface.
Usually you use Class.forName to initialize the class.
I have a situation where I have a registry class to which certain classes have to register themselves for the system. Since I'm writing an API I can't necessarily know which these classes are before runtime, so my solution is using a static block within each class for it to register itself.
The problem is of course that the static block isn't run until each class is initialized, and because there are no explicit references to each individual class, they never are initialized. Catch-22.
So, is there any way or annotation to make sure that a class is initialized at startup without referring to it explicitly?
Spring for instance, does this using the #Component annotation, or any if its subclasses, to scan for annotated classes at runtime. You could use spring for this, implement such functionality for yourself, or use a dedicated library such as scannotation.
If you decide to look into spring, you can use the bean ClassPathScanningCandidateComponentProvider standalone to scan for classes with a given annotation.
If you're not running in some sort of container environment (e.g. using OSGI,Spring,Guice etc..), there's no general way yet without making it explicit. You can take the approach of JDBC, in which the user of a particular JDBC driver library have to make sure the driver is initialized before use,
i.e. someone have to run e.g.
Class.forName("org.postgresql.Driver"); , which will load the org.postgresql.Driver class. In that class you can have a static initializer which also loads/registers all the other classes you need.
Say. jdbc driver need Class.forName to exec static block of a class.
Why not just run it as a class field?
Class.forName() is guaranteed to initialize the class at the time you call it. How would you propose to do it? Could you just declare a local variable without assigning it, like com.foo.Driver d;? What about a making it a member variable instead? Would you have to actually assign it? What does the spec say about how and when a class has to be loaded? Do you really want to have to think about that, or just call Class.forName()?
On a related note, it's no longer necessary to do this with many JDBC drivers. The DriverManager now uses the ServiceLoader mechanism to identify and load conforming driver classes.
The whole idea of JDBC is to not be dependant on one specific driver or implementation. The idea is you can use JDBC and configure at runtime any driver which is available. To do this you need to load the driver by name and use the JDBC methods. Unfortunately JDBC doesn't abstract away all the differences between databases like error codes, and switching to a database you haven't tested may not be a good idea.
You could take the view that for all of your libraries, you have them available at compile time and you wouldn't change the database on a wim, without a minimum re-testing and re-deploying your application. In this case linking to a specific driver (instead of using Class.forName) might be a good thing because it would force you (or whomever does this) to put more thought into the change and follow your testing procedures.
It's impractical to use technique for loading JDBC drivers other than reflection.
(Though there are different ways to do it). There's a lot of JDBC drivers and the implementation code may not be available to the app.