Spring Interview Questions and Answers Q1 - Q14 are FAQs
Q15. How would you integrate Hibernate with Spring?
A15. The hibernate can be wired up via Spring as shown below.
STEP 1: The Hibernate properties.
<!-- hibernate properties-->
<bean id="myappHibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SybaseDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
</props>
</property>
</bean>
STEP 2: The DataSource.
<!-- datasource configured via JNDI-->
<bean id="myappDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/dataSource/myapp-ds</value>
</property>
</bean>
STEP 3: The hibernate mapping files. The mapping file tells Hibernate what table in the database it has to access, and what columns in that table it should use.
<bean name="myappHibernateMappingFiles" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<value>hbm/Order.hbm.xml</value>
<value>hbm/Trade.hbm.xml</value>
<value>hbm/Customer.hbm.xml</value>
</list>
</property>
</bean>
STEP 4: An empty interceptor
<!-- An interceptor that does nothing. May be used as a base class for application-defined custom interceptors. -->
<bean id="myappEntityInterceptor" class="org.hibernate.EmptyInterceptor" />
STEP 5: Usually an application has a single SessionFactory instance and threads servicing client requests obtain Session instances from this factory.
<!-- Define the session factory -->
<bean name="myappSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" autowire="byName">
<property name="hibernateProperties">
<ref bean="myappHibernateProperties"/>
</property>
<property name="dataSource">
<ref bean="myappDataSource"/>
</property>
<property name="mappingResources">
<ref bean="myappHibernateMappingFiles"/>
</property>
<property name="entityInterceptor">
<ref bean="myappEntityInterceptor"/>
</property>
</bean>
STEP 6: The hibernate template. Helper class that simplifies Hibernate data access code.
<!-- Hibernate Template -->
<bean name="myappHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" autowire="no" scope="prototype">
<property name="sessionFactory">
<ref bean="myappSessionFactory"/>
</property>
<property name="allowCreate">
<value>false</value>
</property>
<property name="maxResults">
<value>50000</value>
</property>
<property name="flushMode">
<value>3</value>
</property>
</bean>
STEP 7: The repository class for data access logic.
<!-- Constructor Inject the Template into your Repository classes (Data acess layer) -->
<bean id="myappOrderRepository" class="com.HibernateOrderRepository">
<constructor-arg><ref bean="myappHibernateTemplate" /></constructor-arg>
</bean>
STEP 8: The service class that uses one or more repositories.
<!-- Service Layer: myappOrderRepository is injected via setter injection -->
<bean id="myappOrderService" class="com.OrderServiceImpl">
<property><ref bean="myappOrderRepository" /></property>
</bean>
STEP 9: The repository interface and class that makes use if the hibernate template.
package com;
import com.ObjectNotFoundException;
public interface OrderRepository {
public Order load(Long identity) throws ObjectNotFoundException;
public void save(Order order);
}
The template.load, template.save, etc are database operations via the HibernateTemplate.
package com;
import org.apache.log4j.Logger;
import org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.HibernateTemplate;
import com.ObjectNotFoundException;
import com.Order;
import com.OrderRepository;
public class HibernateOrderRepository implements OrderRepository {
private static final Logger LOG = Logger.getLogger(HibernateOrderRepository.class);
private final HibernateTemplate template;
public HibernateOrderRepository(HibernateTemplate template) {
this.template = template;
}
@Override
/**
* Read Order from database
*/
public Order load(Long identity) throws ObjectNotFoundException {
if (LOG.isDebugEnabled()) {
LOG.debug("Loading " + identity);
}
try {
return template.load(Order.class,identity);
} catch (HibernateObjectRetrievalFailureException e) {
throw new ObjectNotFoundException(identity + " not found", e);
}
}
/**
* Save the record to database
* @param order */
public void save(Order order) {
if (LOG.isDebugEnabled()) {
LOG.debug("Saving " + order);
}
template.save(order);
}
}
Q16: How do you wire up a transaction manager?
A16:
STEP 1: Define a transaction manager.
<!-- Transaction Manger -->
<bean name="myappTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="myappSessionFactory" />
</bean>
STEP 2: Create a transaction interceptor that uses the above transaction manager.
<bean id="myappHibernateInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="myappTransactionManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
STEP 3: Create other optional interceptors for logging, deadlock retry, etc.
<!-- SERVICE INTERCEPTORS -->
<bean id="myappLoggingInterceptor" class="com.MyAppLoggingInterceptor" />
<bean id="myappDeadlockRetryInterceptor" class="com.OracleDeadlockRetryInterceptor" />
STEP 4: Wire up the interceptors to an abstract service
<!-- SERVICES -->
<bean id="myappAbstractService" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>myappLoggingInterceptor</value>
<value>myappDeadlockRetryInterceptor</value>
<value>myappHibernateInterceptor</value>
</list>
</property>
</bean>
STEP 5: The concrete service that uses the myappOrderRepository along with the interceptors. Especially the "myappHibernateInterceptor" that performs transaction demarcation.
<bean id="myappOrderService" parent="myappAbstractService">
<property name="proxyInterfaces">
<value>com.mgl.mts.oms.model.service.OrderService</value>
</property>
<property name="target">
<bean class="com.OrderServiceImpl">
<constructor-arg><ref bean="myappOrderRepository" /></constructor-arg>
</bean>
</property>
</bean>
STEP 6 The OrderServiceImpl class looks like
package com;
import ....
public class OrderServiceImpl implements OrderService {
private final Logger LOG = Logger.getLogger(OrderServiceImpl.class);
private final OrderRepository orderRepository;
public OrderServiceImpl(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
//......
}
Note: The
OrderServiceImpl will have the interceptors turned using AOP to manage transaction, logging, and deadlock retry. The diagram below gives a big picture of interceptors, service, and repository.
Note: The deadlock retry filter is an interesting one. When an exception is thrown, it is inspected using a pattern matching (i.e. regular expression) to see if it is due to deadlock. If it is due to deadlock the invocation is repeated. This makes the call again to the target, which is the
OrderServiceimpl via the
TransactionInterceptor, which starts a new transaction.
Here is an example of the custom interceptor -- myappLoggingInterceptor. Aspect-Oriented Programming (AOP) offers a better solution to many problems. he AOP Alliance project (aopalliance-x.x.jar) is a joint open-source project between several software engineering people who are interested in AOP and Java.
package com.test;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
public class MyAppLoggingInterceptor implements MethodInterceptor {
private static final Logger LOG = Logger.getLogger(MyAppLoggingInterceptor.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
long begin = System.currentTimeMillis();
//proceed to the next interceptor on the chain
Object result = invocation.proceed();
long end = System.currentTimeMillis();;
LOG.info("Time elapsed " + (end - begin) + " ms");
return result;
}
}
The deadlock retry interceptor
package com.test;
import java.sql.SQLException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
public class OracleDeadlockRetryInterceptor implements MethodInterceptor {
private static final Logger LOG = Logger.getLogger(OracleDeadlockRetryInterceptor.class);
private int attempts = 3;
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
return doInvoke(invocation, 1);
}
private Object doInvoke(MethodInvocation invocation, int count) throws Throwable {
try {
//proceed to next interceptor
return invocation.proceed();
} catch (Exception exception) {
if (!isDeadlockException(exception)) {
throw exception;
}
LOG.warn("A Database deadlock occured. Will try again.", exception);
if (count < attempts) {
count++;
return doInvoke(invocation, count);
}
throw new SQLException("Service Invocation failed " + attempts
+ " times with a SQLException.", exception);
}
}
}
More Spring Interview Questions and Answers
Labels: Hibernate, Spring