Reputation: 983
So, every Java text book talks about how flexible Java is since it can load classes at run time. Just cobble together a string and give it to Class.forName()
, and catch the ClassNotFoundException
and handle it. So much for the theory.
Can you give examples of how you've been using Java class loading to achieve a feature which otherwise wouldn't have been possible or easy? Note that I'm not asking "what great things could we do?" - I'm looking for real-world examples, be it an open-source application or - if you can describe this without giving out too much details - a proprietary application.
Edit: Sure, the VM loads classes lazily as it needs them. That's a behind-the-scenes thing as long as I'm sure that all classes I'll ever need are there. How do I handle a ClassNotFoundException
? Suppose I've written ten pages worth of text, and the PrinterDriver
class can't be found.
Upvotes: 18
Views: 2106
Reputation: 41087
Any framework that is configuration based (struts, jsf, spring, hibernate, etc.) uses this mechanism. Any product that is based on the plugin architecture also uses this feature.
Upvotes: 0
Reputation: 1
Using the dynamic class loading is also very useful for loading configuration files as Thilo mentions. More generally, dynamic class loading can make a nice file system abstraction layer in many situations, simplifying writing preference and config sensitive code. Just make sure the resource you need is on the classpath and load it as an InputStream.
Furthermore, with a custom protocol handler in Java it is possible to access items on the classpath via URL. This isn't an advantage specific to dynamic class loading, but it does demonstrate how classpath resources can be accessed via the same API as other resources (even remote ones). http://java.sun.com/developer/onlineTraining/protocolhandlers/
Upvotes: 0
Reputation: 70201
The Java classloader mechanism is powerful because it provides an abstraction point at exactly the point where code is loaded, which lets you do things such as:
On the point of modifying code during load, there are a world of interesting things you can do to remix your code - AOP, profiling, tracing, behavior modifications, etc. At Terracotta we relied on the classloader abstraction to dynamically load a class, then intercept all access to fields and dynamically add the ability to load state from the same object at a remote node in the cluster later. Cool stuff.
Upvotes: 1
Reputation: 25687
"PLUGIN" and that is the big word.
Basically, you can load a class that you do not know when or does not exist when you write and compile your program.
For example, if you want a program to do spell check, you can write an interface SpellChecker
then load a class from a configuration file that implement the SpellChecker
interface. After that, you can write any SpellChecker and set in the configuration file the actual file name. This way, your program does not need to know what class will do the spell checking.
DB driver, Eclipse's plugin, Script language, Cryptography methods are all done this way as the original writer does not know (and in some case, has no idea) what class will actually be used.
Hope this helps.
Upvotes: 6
Reputation: 1108632
The JDBC API is an excellent example for this. This way you can configure the JDBC driver externally in for example a properties file:
driver = com.dbvendor.jdbc.Driver url = jdbc:dbvendor://localhost/dbname username = stackoverflow password = youneverguess
..which you can use as:
Properties properties = new Properties();
properties.load(Thread.currentThread().getResourceAsStream("jdbc.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password);
Every JDBC driver implementation basically registers itself in the DriverManager
inside a static
initializer block. It's namely the one which get executed during Class#forName()
.
package com.dbvendor.jdbc;
public class Driver implements java.sql.Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
private Driver() {
// ...
}
public boolean acceptsURL(String url) {
return url.startsWith("jdbc:dbvendor");
}
}
Since the DriverManager
roughly look like this (it actually uses the old fashioned Vector
)
private static final Set<Driver> drivers = new HashSet<Driver>();
public static void registerDriver(Driver driver) {
drivers.add(driver);
}
public static Connection getConnection(String url, String username, String password) throws SQLException {
for (Driver driver : drivers) {
if (driver.acceptsURL(url)) {
return driver.connect(url, username, password);
}
}
throw new SQLException("No suitable driver");
}
...you can get a connection from it without the need to instantiate the driver itself!
This way the JDBC code is highly portable. You can change the DB or distribute the code among users with different DB's without the need to change/hack/rebuild the code itself.
It's not only JDBC which uses this approach, also other API's such as Servlet API, ORM's like Hibernate/JPA, dependency injection frameworks, etcetera uses reflection to load the classes based on externally configureable propertiesfiles, XML config files and/or annotations. It all just makes the code much more portable and pluggable.
Upvotes: 2
Reputation: 28293
Real-world example (as requested in your question), proprietary application (as explicitely allowed by your question)...
Upon startup, the client-side software contacts our server(s) and says "Default implementation of interface Bar I have is Foo (because actually every version 1.03, for example, are using Foo), do you have a better one?" If meanwhile we wrote a better implementation, we answer "yup, Bar is old, use Buz, it's better".
Then on the client side a class loader is used to load the latest implementation.
It's oversimplified but it's a real world example. It's not entirely dissimilar to the example JRL mentioned: where deprecated classes are automagically replaced by newer ones.
Upvotes: 0
Reputation: 8153
Plugins is the first thing that comes to mind. Java class loading makes it very easy compared to languages like C++.
One point that you may not be aware of is that any Java virtual machine heavily relies on class loading internally. Everytime a reference to, say, a method is seen by the bytecode interpreter, it checks whether the class the method belongs to is already loaded, and if it is not, loads it using the very same mechanism behind Class.forName()
before resolving the method. This mecanism is very powerful as any Java application truly acts as a set of replaceable components which are all dynamically loaded. If the VM is well written it can for instance load classes through a custom class loader that fetches classes from the network instead of regular files.
The class loading time depends on the virtual machine implementation, but most rely on this late-binding mechanism that loads a class the first time the VM meets it.
Upvotes: 10
Reputation: 21186
I remember creating a class loader to load classes remotely. The application was running on one node while the classes were stored on another node.
And also by customising the class loader you can transform classes as they are loaded. This is used by some ORM frameworks as well as some AOP frameworks.
Upvotes: 2
Reputation: 5254
Servlet containers like Tomcat read your war/webapp configuration file from WEB-INF/web.xml and load your Servlet/Filter/etc. subclasses based on the String values you put in the XML file. For database connections, they pull the class name to load from your configuration, e.g. "com.mysql.jdbc.Driver" for MySQL.
Upvotes: 0
Reputation: 38605
Application Servers rely also heavily on ClassLoaders
to isolate the different deployed module. E.g.
Thanks to the magic of class loaders...
Upvotes: 5
Reputation: 8214
See the support for Oracle LOB handling in Spring Framework for example. Only because the framework offers specific support for Oracle you probably don't want to deploy an Oracle datasource as dependency for your e.g. MySQL projects. Therefore you load the Oracle drivers reflectively in the scope of an instance of the LOB handler.
Upvotes: 0
Reputation: 485
You can use the Class::forName method if the class is in the class path. However if you need to give a path along with the class name i.e c:\document\xyz.class you will have to use the URLClassLoader class.
Upvotes: -2
Reputation: 9044
i think JUnit may also used a lot of reflection features to make the test framework generic.
Upvotes: 1
Reputation: 262474
The ClassLoader is also used for non-class resources. Configuration files come to mind. Since there is a well-defined search order, it is easy to drop-in your own "log4j.xml" or "hibernate.properties", and the application will find and use it.
Upvotes: 2
Reputation: 77995
It can be extremely useful in situations where you're using an API and the API designers actually deprecated some classes from one version to the next (for example the Contacts in Android).
Without reflection and dynamic class loading based on the string name, it would be impossible in this instance to have the same program run on both versions of the platform without getting a class not found exception at runtime. But with it, the same program was tweaked a bit and then could run on both platforms.
Upvotes: 2
Reputation: 19863
I'm pretty sure plugin loading in Java relies much on that.
The application checks for named functions and executes them
Eclipse actually uses that for plugins
The key idea is to execute code that wasn't planned at developpement time.
Upvotes: 2
Reputation: 718718
I use it when I'm building an off-the-shelf application that needs to be tailored by myself or the customer to meet the customer's specific requirements.
Upvotes: 0
Reputation: 881153
Well, I've used it for dynamically loading JDBC drivers into a J2EE application. Wheteher this could have been done a better way, I have no idea.
It was just easier at the time to do the forName()
call.
Upvotes: 3