Váš košík je aktuálně prázdný!
Použití EJB ve Springu
Před časem jsem na projektu řešil, jak použít dependency injection Springu pro použití EJB. V podstatě mi šlo o to, abych nemusel řešit různé lookupy na EJB v kódu, ale aby to vše fungovalo tak nějak „samo“.
V případě EJB 2, je to snadné. Spring poskytuje celkem snadné prostředky:
Jednoduché natolik, že LocalStatelessSessionProxyFactoryBean ví, jak vytvořit instanci Beanu, přes Home rozhraní, na které ukazuje JNDI. Existuje několik různých proxy factory, pro různé druhy EJBček.
V EJB3 je situace jiná, protože vůbec nemusíte implementovat Home rozhraní. Důsledkem je, že nemůžete používat LocalStatelessSessionProxyFactoryBean. Namísto toho, používáte standardní JndiObjectFactoryBean:
Princip je jednoduchý: najde EJB v JNDI, zaregistruje se jako spring Bean, a pak se přes autowiring předá tato reference do jiného beanu. To zní dobře.
Má to jeden zásadní problém: musíte definovat EJBčka v XML. Jednou z obrovských výhod EJB 3 je to, že nemusíte řešit žádné XML soubory (známe XML hell z EJB 2.x). A to se mi nechce měnit.
Naštěstí je tu řešení: BeanPostProcessors. BeanPostProcessors vám umožňuje dělat věci, nad jednotlivými beany po jeho vytvoření. A to třeba vyhledání metod, anotací apod. Například anotace @EJB
Zde je kód:
/** Look for EJB3-style annotations, and provide the corresponding values from the container. */
public class EjbBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
// do nothing; the EJBs are configured before initialization.
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
Class beanClazz = bean.getClass();
for (Method method : beanClazz.getMethods()) {
if (method.isAnnotationPresent(EJB.class)) {
setEjbRef(bean, method);
}
}
return bean;
}
private void setEjbRef(T bean, Method setter) {
Class ejbClass = determineBeanClass(setter);
Object ejbBean = lookupBean(ejbClass, determineJndiName(ejbClass, setter), bean);
invoke(bean, setter, ejbBean);
}
/**
* Determine the JNDI name for the EJB. By default, we assume that it is the simple class
* name, but we allow the setter method to override this, using the 'mappedName' attribute.
*/
private String determineJndiName(Class ejbClass, Method setter) {
EJB ejbAnnotation = setter.getAnnotation(EJB.class);
if (ejbAnnotation.mappedName().equals("")) {
return ejbClass.getSimpleName();
}
return ejbAnnotation.mappedName();
}
private Object lookupBean(Class ejbClass, String beanName, Object bean) throws BeansException {
try {
return new InitialContext().lookup("java:comp/env/ejb/" + beanName);
} catch (NamingException e) {
throw new EjbBeansException(bean, "Could not resolve EJB " + beanName, e);
}
}
/**
* Determine the type of the EJB. This is used to determine the JNDI name to look up. This
* would normally be the type of the argument to the setter, but the EJB spec allows this
* to be overriden (presumably to a subclass)
*/
private Class determineBeanClass(Method setter) {
EJB ejbRefAnnotation = setter.getAnnotation(EJB.class);
if (ejbRefAnnotation.beanInterface() != null &&
Object.class.equals(ejbRefAnnotation.beanInterface()) == false) {
return ejbRefAnnotation.beanInterface();
}
Class otherBeanClass = setter.getParameterTypes()[0];
return otherBeanClass;
}
private void invoke(T bean, Method method, Object ... args) {
try {
method.invoke(bean, args);
} catch (IllegalArgumentException e) {
throw new EjbBeansException(bean, "Could not set EJB", e);
} catch (IllegalAccessException e) {
throw new EjbBeansException(bean, "Could not set EJB", e);
} catch (InvocationTargetException e) {
throw new EjbBeansException(bean, "error setting EJB reference", e.getCause());
}
}
/** Simple exception detailing the type of problem that occured. */
private static class EjbBeansException extends BeansException {
public EjbBeansException(Object bean, String message, Throwable cause) {
super(message + " [bean class: " + bean.getClass().getName() + "]", cause);
}
}
}
Tento krásný BeanPostProcessor ve Springu ho aktivujeme celkem snadno:
Teď si prostě přidáte anotaci @EJB odkazy do svého Spring beanu, a on se kouzelně naplní. Do žádného XML není potřeba nic definovat. Jak krásné.
Categories:
Leave a Reply