Итак, до весны мы использовали версию HibernateUtil, которая кэшировала экземпляр SessionFactory, если было установлено успешное необработанное соединение JDBC, и в противном случае вызвала SQLException. Это позволило нам восстановить «первоначальную» настройку SessionFactory как «плохую» из-за проблем с аутентификацией или подключением к серверу.
Мы перешли на Spring и более или менее классическим образом подключили объекты с LocalSessionFactoryBean, источником данных C3P0 и различными классами dao, в которые вставлен SessionFactory.
Теперь, если сервер SQL не работает во время работы веб-приложения, оно никогда не восстанавливается. Весь доступ к методам dao прерывается, потому что вводится нулевая сессионная фабрика. (как только сессионная фабрика выполнена правильно, пул соединений в основном обрабатывает состояние up / down сервера sql нормально, поэтому восстановление возможно)
Теперь методы dao по умолчанию связаны как одиночные, и мы можем изменить их на прототип. Я не думаю, что это решит проблему, хотя - я считаю, что LocalSessionFactoryBean теперь "застрял" и кеширует нулевую ссылку (хотя я еще не проверял это, хотя я постыдно признаю)
Это должно быть проблемой, касающейся людей.
Попробовал прокси как предложено ниже - это не удалось
Прежде всего я должен был проигнорировать предложение (которое откровенно казалось неправильным из декомпиляции) для вызова LocalSessionFactory.buildSessionFactory
- его не видно.
Вместо этого я попробовал модифицированную версию следующим образом:
переопределить newSessionFactory. В конце верните прокси SessionFactory
, указывающий на обработчик вызова, указанный ниже
Это тоже не удалось.
org.hibernate.HibernateException: не найден локальный источник данных для конфигурации - для LocalSessionFactoryBean должно быть установлено свойство 'dataSource'
Теперь, если newSessionfactory()
изменяется на просто
return config.buildSessionFactory()
(вместо прокси) работает, но, конечно, больше не демонстрирует желаемого поведения прокси.
public static class HibernateInvocationHandler implements InvocationHandler {
final private Configuration config;
private SessionFactory realSessionFactory;
public HibernateInvocationHandler(Configuration config) {
this.config=config;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (false) proxy.hashCode();
System.out.println("Proxy for SessionFactory called");
synchronized(this) {
if (this.realSessionFactory == null){
SessionFactory sf =null;
try {
System.out.println("Gonna BUILD one or die trying");
sf=this.config.buildSessionFactory();
} catch (RuntimeException e) {
System.out.println(ErrorHandle.exceptionToString(e));
log.error("SessionFactoryProxy",e);
closeSessionFactory(sf);
System.out.println("FAILED to build");
sf=null;
}
if (sf==null) throw new RetainConfigDataAccessException("SessionFactory not available");
this.realSessionFactory=sf;
}
return method.invoke(this.realSessionFactory, args);
}
}
Создание прокси в newSessionFactory выглядит следующим образом
SessionFactory sfProxy= (SessionFactory) Proxy.newProxyInstance(
SessionFactory.class.getClassLoader(),
new Class[] { SessionFactory.class },
new HibernateInvocationHandler(config));
и можно вернуть этот прокси (который не работает) или config.buildSessionFactory (), который работает, но не решает начальную проблему.
Божо предложил альтернативный подход с использованием getObject (). Обратите внимание на фатальную ошибку в d), потому что buildSessionFactory не виден.
а) если this.sessionfactory не нулевой, прокси не нужен, просто верните
б) если это так, создайте прокси, который ...
c) должен содержать частную ссылку на sessionfactory, и каждый раз, когда она вызывается, проверять, является ли она пустой Если это так, вы создаете новую фабрику и в случае успеха назначаете частную ссылку и возвращаете ее с этого момента.
г) Теперь укажите, как бы вы построили эту фабрику из getObject (). Ваш ответ должен включать вызов buildSessionFactory .... но вы НЕ МОЖЕТЕ. Можно создать фабрику самостоятельно, но вы рискуете сломать пружину таким образом (посмотрите код buildSessionFactory)