dagblog.
← Archiv

Odložené nahrávání dat v ORM nástrojích


Odložené nahrávání dat, takzvaný lazy fetching, patří k základním vlastnostem pro
zvýšení výkonu v ORM nástrojích jako Hibernate či iBatis SQL Maps. Představme si případ kdy máme dvě entiy entity ve
vztahu 1:* např. osoba a auto.

public class Osoba {

private Set auta;

public Set getAuta() {

return auta;

}

public void setAuta(Set auta) {

this.auta = auta;

}

}

Odložené nahrávání může být v tomto případě použito na kolekce automobilů a
to následujícím způsobem. Kolekce automobilů je z databázé dotažena teprve ve chvíli
kdy je volána metoda getAuta(). Díky odloženému nahrávání je tak možné data
načíst teprve ve chvíli kdy je to opravdu potřeba.

Otázka je jak výše uvedený getter zajistí nahrání dat z databáze? Samozřejmě, že nezajistí, to co ho
zajistí se jmenuje dynamický proxy objekt. ORM framework totiž nikdy nevrací přesně objekt dané
třídy nýbrž v runtime čase dynamicky vytvořeného potomka dané třídy. Díky dědičnosti je pro vás práce s
objektem, v našem případě Auto, transparentní. Potomek pak slouží jako proxy objekt, který realizuje
odložené nahrání dat.

Pro lepší znázornění výše popsaného, kód který vznikne semanticky odpovídá následujícímu kódu.

public class OsobaProxy extends Osoba {

public Set getAuta() {

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

setAuta(auta);

return super.getAuta();

}

}

Hibernate tak iBatis používá na vytváření proxy objektů v runtime framework zvaný CGLIB. Jak je 
jednoduché s CGLIBem pracovat si ukážeme na následujícím příkladu, třeba se vám to bude hodit. Vytvoříme jednoduchou beanu a k ní v runtime proxy objekt, 
který při každém volání metody naší beany vypíše název této metody.

Vlastní beana

/**

* 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, třída která bude zavěšená na volání metod beany. V interceptoru se nejdříve vypíše název volané metody a následně se nechá vykonat původní metoda beany.

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);

}

}

Ukázka vytvoření dynamické proxy beany a jejího volání. Všimněte si zavěšení interceptoru.

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;

}

}

Verze na Medium

Související články

Související epizody CZ Podcastu