Ваш код выглядит так, как будто вы не полностью поняли концепцию внедрения зависимостей Spring, потому что ваш BaseController
выполняет работу Spring по управлению синглетами и поддержке зависимостей.
Задача
Вы создаете EventController
и PersonController
экземпляры самостоятельно внутри BaseController
вместо того, чтобы полагаться на Spring.Spring не может перехватить ручное создание экземпляров классов и предоставить им требуемое здесь транзакционное поведение, пометив классы аннотацией Spring @Transactional
.
Solution
Итак, давайте найдем путь для очистки этого кода.Сначала удалите класс HibernateUtil
, поскольку он представляет собой смесь статических вызовов, концепций Java-бинов и неиспользуемого поведения транзакций, в то время как он приносит новый уровень абстракции без каких-либо преимуществ.Не забудьте удалить его из applicationContext.xml
также.
Теперь удалите BaseController
из вашего applicationContext.xml
также и дайте ему основную переписку, потому что он работает как Singleton-Factory для ваших PersonController
и EventController
, который будет правильно управляться самой Spring в такой среде.
public abstract class BaseController {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
protected Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
Таким образом BaseController
становится абстрактным базовым классом для других расширяющих классов, которые могут использовать предоставленный Hibernate Session
объект.Теперь давайте создадим красивый интерфейс для вашего EventController
.
public interface EventController {
Event getEventById(long id);
void deleteEventById(long id);
Event createEvent(String name);
List getEvents();
}
Далее нам потребуется реализация вышеуказанного интерфейса для Hibernate, поэтому давайте вызовем новый класс EventControllerHibernate
, используя ранее созданный BaseController
реализация.
public class EventControllerHibernate extends BaseController implements EventController {
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public Event getEventById(long id) {
return (Event) getCurrentSession().get(Event.class, id);
}
@Transactional(propagation = Propagation.REQUIRED)
public void deleteEventById(long id) {
getCurrentSession().delete(getEventById(id));
}
@Transactional(propagation = Propagation.REQUIRED)
public Event createEvent(String name) {
return (Event) getCurrentSession().save(new Event(name));
}
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
@SuppressWarnings("unchecked")
public List getEvents() {
return getCurrentSession().createQuery("from Event").list();
}
}
И не забудьте правильно зарегистрировать этот класс в своей Spring applicationContext.xml
, чтобы обеспечить требуемый SessionFactory
:
<bean id="eventController" class="com.epa.controller.EventControllerHibernate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Если вы получаетеSpring bean типа EventController
от Spring, вы получите прокси-объект с поддержкой транзакций, полностью реализующий ваш интерфейс EventController
, делегирующий бизнес-логике, реализованной внутри EventControllerHibernate
.
Помните : new EventControllerHibernate()
никогда не должно появляться в вашем приложении, так как это не сработает, потому что Spring не может перехватить ручное создание экземпляра класса!Получение экземпляра с поддержкой транзакций программно будет выглядеть так:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
EventController eventController = context.getBean("eventController", EventController.class);