dagblog.
← Archive

Lazy loading in ORM tools


Lazy loading, also called lazy fetching, is one of the basic ways to
improve performance in ORM tools such as Hibernate or iBatis SQL Maps. Imagine two entities with a
1:* relationship, for example a person and a car.

public class Osoba {

private Set auta;

public Set getAuta() {

return auta;

}

public void setAuta(Set auta) {

this.auta = auta;

}

}

In this case, we can use lazy loading for the collection of cars in
the following way. The collection is fetched from the database only when
the getAuta() method is called. Lazy loading lets us fetch the data
only when we actually need it.

How does the getter above load the data from the database? Of course, it doesn't. What does the work
is called a dynamic proxy object. An ORM framework returns a subclass created at runtime,
instead of an instance of the exact class requested. Inheritance makes working with the object, an instance of Auto in our example,
transparent to the caller. The subclass acts as a proxy object that performs
the lazy loading.

To illustrate the idea, the resulting code is semantically equivalent to the following.

public class OsobaProxy extends Osoba {

public Set getAuta() {

Set auta = ... //volani logiky pro nacteni dat

setAuta(auta);

return super.getAuta();

}

}

Hibernate and iBatis both use a framework called CGLIB to create proxy objects at runtime. The next example shows how
easy CGLIB is to work with. You might find it handy. We will create a simple bean and a proxy for it at runtime.
The proxy prints the name of each bean method when that method is called.

The bean itself

/**

* Klasicka Java bean

*/

public class Bean implements Serializable{

private int foo;

public int getFoo() {

return foo;

}

public void setFoo(int foo) {

this.foo = foo;

}

}

Interceptor is the class hooked into calls to the bean's methods. The interceptor first prints the name of the method being called, then runs the original bean method.

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

/**

* Interceptor, ktery je zavesen na volani jakekoliv metody {@link cz.sweb.pichlik.examples.lazyinit.Bean}

*/

public class Interceptor implements MethodInterceptor {

/**

* Vypise nazev volane metody

*/

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

System.out.println("Volana metoda:" + method.getName());

return proxy.invokeSuper(obj, args);

}

}

An example of creating a dynamic proxy for the bean and calling it. Notice how the interceptor is attached.

import net.sf.cglib.proxy.Enhancer;

/**

* Demonstruje instrumentaci Java beany viz {@link cz.sweb.pichlik.examples.lazyinit.Interceptor}

*

*/

public class LazyInitExample {

public static void main(String[] args) {

Bean instrumentedBean = (Bean) createNewInstrumentedBean(Bean.class);

instrumentedBean.setFoo(10);

instrumentedBean.getFoo();

}

/**

* Vytvori rozsirenou instanci objektu dane tridy.

*

* @param clazz trida

* @return instance

*/

private static Object createNewInstrumentedBean(Class clazz){

Interceptor interceptor = new Interceptor();

Enhancer e = new Enhancer();

e.setSuperclass(clazz);

e.setCallback(interceptor);

Object instrumentedBean = e.create();

return instrumentedBean;

}

}

Medium version

Related articles

Related CZ Podcast episodes