Classloading and Type Visibility in OSGi
Martin
M ti Lippert
Li t
akquinet it-agile GmbH
[email protected]
© 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license | November 4th, 2008
Overview
• Introduction to classloading
What is classloading?
How does classloading work?
What does classloading mean for daily development?
• Classloading in OSGi
What is different?
Dependency and visibility
Advanced classloading in OSGi
Some Equinox specifics
• Conclusions
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
What is Classloading?
• Classloaders are Java objects
• They are responsible for loading classes into the VM
Every
y class is loaded byy a classloader into the VM
There is no way around
• Every class has a reference to its classloader object
myObject.getClass().getClassLoader()
Obj t tCl () tCl L d ()
• Originally motivated by Applets
To load classes from the server into the browser VM
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Classloader API
public abstract class ClassLoader {
p
public Class<?> loadClass(String name)
public URL g
p getResource(String
( g name)
)
public Enumeration<URL> getResources(String name)
public InputStream getResourceAsStream(String name)
public final ClassLoader g
p getParent()
()
public static URL getSystemResource(String name)
public static Enumeration<URL> getSystemResources(String name)
public
p static InputStream
p getSystemResourceAsStream(String
g y g name)
public static ClassLoader getSystemClassLoader()
...
}
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Implicit class loading
public class A {
public void foo() {
B b = new B();
b.sayHello();
causes the VM to load
}
class B using the
}
classloader of A
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Dynamic class loading
public void foo() {
ClassLoader cl =
this.getClass().getClassLoader();
Class<?> clazz = cl.loadClass("A");
Object obj = clazz.newInstance();
...
}
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Hierarchical classloaders
• Classloaders typically have a parent classloader
Chained classloading
• If a classloader is invoked to load a class, it first calls
the parent classloader
Parent
P t first
fi t strategy
t t
This helps to prevent loading the same class multiple times
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Classloader hierarchy
Class A
Classloader A A.jar
parent
Class B
Classloader B
B.jar
loaderB.loadClass("A");
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type compatibility
Class A
Classloader A A.jar
loaderA.loadClass("A");
parent
Class B
Classloader B
B.jar
Returns the same class object as
loaderB.loadClass("A")
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Defining vs. Initiating classloader
Defining loader
Initiating loader
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type compatibility II
Class A
Classloader A A.jar
parent parent
Class B Class B
Classloader B1 Classloader B2
B.jar B.jar
loaderB1.loadClass(“A”) == loaderB2.loadClass(“A”)
loaderB1.loadClass(“B”) != loaderB2.loadClass(“B”)
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type compatibility III
Class A
Classloader A A.jar
parent parent
Class B Class B
Classloader B1 Classloader B2
B jar
B.jar B jar
B.jar
Object b1 = loaderB1.loadClass(“B”).newInstance();
b1 !instanceof loaderB2.loadClass(“B”)
Remember: a class is identified by its name (including the
package name) AND its defining classloader !!!
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type compatibility IV
Class A
Classloader A A.jar
public interface A {}
parent parent
Class B Class B
Classloader B1 Classloader B2
B.jar
j B.jar
j
public class B implements A {}
A anA = loaderB1.loadClass(
loaderB1.loadClass(“B”).newInstance();
B ).newInstance();
A anotherA = loaderB2.loadClass(“B”).newInstance();
anA = anotherA; (Assignment)
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
The default setting
Bootstrap Classloader loads JVM classes (rt.jar)
loads classes from the
Extension Classloader JRE ext folder
loads classes from your
System Classloader application classpath
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
A typical setting…
bcel oracle json
rt content dbcp log4j
jce naming aspectjrt axis
jsse core logging resource
plugin commons poi
marketing guiapp lucene
spring hibernate jdom
asm cglib utils
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Threads context classloader
Thread.currentThread().getContextClassLoader()
Thread currentThread() getContextClassLoader()
Thread.currentThread().setContextClassLoader(..)
• Typically used in libraries to access the context in
which the library is called
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Classloader.loadClass vs. Class.forName
•Classloader.loadClass()
Cl l d l dCl () caches the loaded class
object and returns always the same class object
This is done by the defining classloader
This ensures that each classloader loads the same class only
once
•Class.forName()
Class.forName() calls the normal classloader
hierarchy to load the class (same happens as above)
But caches the class object within the initiating
classloader
In standard cases no problem but can be tricky in dynamic
environments
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Classloading is dynamic
• You can create classloaders at runtime
• You can trigger them to load a specific class
• For example:
What app/web servers do for hot deployment
• Some
S people
l say th
the classloading
l l di mechanism
h i iis th
the
only real innovation in the Java programming language
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Classloading in OSGi
• “OSGi
OSGi is a service framework”
framework
• What is necessary:
Dependencies between bundles
Import- and Export-Package, Require-Bundle
Dynamic Bundle Lifecycle
Install, Update, Uninstall bundles
• Realized via specialized classloading
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Classloader per bundle
• One classloader per bundle
Controls what is visible from the bundle
Controls what is visible from other bundles
Class A
Classloader
Bundle A
Class B
Classloader
Bundle B
Class C
Classloader
Bundle C
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Classloader per bundle
• Effects
No linear class path for your application anymore
Instead class path per bundle
No real parent hierarchy anymore
• Classloader parent setting
Default: Bootstrap classloader
Can be parameterized via system property
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Dependencies via delegation
Export Package: mypackageA
Export-Package:
Class A
Bundle A
Import-Package: mypackageA, Class B
mypackageC
Bundle B
Class C Export-Package: mypackageC
Bundle C Import-Package: mypackageA
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type Visibility I
Export-Package: mypackageA
Class A
Bundle A
Class B
Import-Package: mypackageA
Bundle B
A anA = new A();
A anA = new A();
class A is loaded only once by
class A is loaded only once by
bundle A (the bundles
bundle A (its defining classloader)
classloader)
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type Visibility II
Export-Package: mypackageA
Class A
Bundle A
Class B
Import-Package: mypackageA
Bundle B
A anA = new A();
A anA = new A();
class is loaded
successfully (if requested
inside bundle A) bundle B remains in state “installed”
(not resolved), no loading of type A
possible
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type Visibility III
Export-Package: mypackageA
Class A
Bundle A
Class B
Import-Package: mypackageA
Bundle B
A anA = new A();
class is loaded A anA = new A();
successfully
ClassNotFoundException
p
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type Compatibility revisited I
Export-Package: mypackageA
Class A
Bundle A
Class B
Import-Package: mypackageA
Bundle B
A anA = new A();
A anotherA = new A();
exactly the same type
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type Compatibility revisited II
Export Package:
Export-Package: Export Package:
Export-Package:
mypackageA;version="1.0.0" mypackageA;version=“2.0.0"
Class A Class A
Bundle A Bundle A
Import-Package: Import-Package:
mypackageA;version=“1
mypackageA;version= 1.0.0
0 0" mypackageA;version=“2
mypackageA;version= 2.0.0
0 0"
Class B Class C
Bundle B Bundle C
A anA = new A(); A anA = new A();
Completely different and incompatible types
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Type Compatibility revisited III Type A
public interface A {} Bundle A
Class B
public class B impl A {}
Bundle B
public class C impl A {}
Class C
Bundle C
Class D
A myA = createServiceA();
Bundle D
Static type of myA is A, dynamic type of myA
could be B or C
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
ClassNotFoundException
• Typical reasons for a ClassNotFoundException:
Dependency to declaring bundle not defined
Type is not visible (not exported)
• Dynamically generated classes
Proxies
CGLib
…
• Serialisation
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Libraries
org.hibernate
• What happens if a library needs B dl
Bundle
to load classes from its clients?
e.g. persistence libraries?
• Cyclic dependencies are not Import-Package:
allowed and maybe even not org hibernate
org.hibernate
what you want Class A
Bundle A
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Register classes
• Register types the library need via an API
E.g.
Hibernate.registerClass(Class clientClass)
• This allows the lib to create objects of those types without
loading
g those classes directlyy
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
DynamicImport-Package
DynamicImport-Package:
y p g *
• Works similar to Import
Import-
org.hibernate
Package, but Bundle
wiring does not happen at resolve
instead at first access to such a
type
• Wildcards possible
* allows a bundle to see Import-Package:
“everything” org.hibernate
Class A
Should be used very rarely,
rarely as
a “last resort” Bundle A
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Equinox buddy loading I
• Equinox provides so called “Buddy
Buddy Loading
Loading”
“I am a buddy of hibernate. Hibernate is allowed to
access my types”
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Equinox buddy loading II
Eclipse-BuddyPolicy: registered
org.hibernate
Bundle
Allows org.hibernate bundle to
execute successfully
loadClass(“A”)
Eclipse-RegisterBuddy:
org.hibernate
Cl
Class A
Bundle A
A anA = new A();
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Equinox buddy loading III
• Important difference:
Buddy loading can load all classes from a buddy bundle
not only exported types
• Its just a workaround for libraries and other existing
code that does not behave correctly within the OSGi
world
• Take care: you could loose consistency
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
CGLib
Bundle
Generated Proxies
• Situation: Spring
Bundle
Ask the Spring bundle for a bean
• What does Spring?
p g
Creates a proxy for the bean using the
classloader of bundle A using CGLib
• The result
The proxy type needs to be loaded by a
classloader that is able to see types from
Class A
bundle A and CGLib
Bundle A
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
The loading sequence
1.
1 Try the parent for “java
java.” packages
2. Try the parent for boot delegation packages
3
3. Try to find it from imported packages
4. Try to find it from required bundles
5. Try to find it from its own class path
6. Try to find it from dynamic import
7. Try to find it via buddy loading
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Garbage Collection for Classloaders
• You could expect that the classloader of a bundle gets
garbage collected if the bundle is stopped or
uninstalled
• This is not automatically the case!!!
• You need to ensure that all objects from those classes
loaded by this classloader are no longer referenced
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
What does this mean?
• Example:
You request an OSGi service and get an OSGi service back
The service you get is provided by bundle A
Next you uninstall bundle A
• If you stay with your object reference to the service
service,
the classloader of A can never be collected
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Service Tracker helps
• Use a Service
Service-Tracker
Tracker
• Takes care of …
holding the reference for performance reasons
As long as the service is available
But
B t no llonger!!
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
“High Performance Classloading”
• Classloading consumes a remarkable amount of time
at startup
• OSGi allows to highly
g y optimize
p classloading
g
Finding the right class
Highly optimized implementations available
Avoid dynamic import
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Classloading Hooks
• Equinox provides a hook mechanism
To enhance and modify the behavior of the runtime
• Examples
Modify bytecode at load-time
Intercept bundle data access
• Eat your own dog food
Some Equinox features are implemented using those hooks
e.g. Eclipse-LazyStart
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Conclusions
• Changing the viewpoint from the linear classpath to a
per-bundle classpath
• Clearlyy defined dependencies
p and visibilities
Real modularity
Classloading only implementation detail
• Use OSGi in a clean and correct way and you
never need to think about classloading
g at all
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license
Thank you for your attention!
Q&A
Classloading and Type Visibility in OSGi | © 2008 by Martin Lippert; made available under Creative Commons Att. Nc Nd 2.5 license