因此,在春季之前,我们使用了 HibernateUtil 版本,如果成功建立原始 JDBC 连接,它会缓存 SessionFactory 实例,否则抛出 SQLException。这使我们能够从由于身份验证或服务器连接问题而导致的 SessionFactory 初始设置“错误”中恢复过来。
我们转向 Spring,并以一种或多或少经典的方式使用 LocalSessionFactoryBean、C3P0 数据源和注入了 SessionFactory 的各种 dao 类来连接事物。
现在,如果 Web 应用程序运行时 SQL Server 似乎未启动,则 Web 应用程序永远不会恢复。所有对 dao 方法的访问都会崩溃,因为注入了空的 sessionfactory。 (一旦sessionfactory正确制作,连接池主要处理sql server的up/down状态,因此可以恢复)
现在,dao 方法默认连接为单例,我们可以将它们更改为原型。我认为这不会解决问题 - 我相信 LocalSessionFactoryBean 现在“卡住”并缓存空引用(不过,我还没有测试过这一点,我会羞愧地承认)。
这一定是人们关心的问题。
尝试了下面建议的代理——失败了
首先,我必须忽略调用的建议(坦率地说,反编译似乎是错误的)LocalSessionFactory.buildSessionFactory
- 它不可见。
相反,我尝试了修改后的版本,如下所示:
覆盖 newSessionFactory。最后返回代理SessionFactory
指向下面列出的调用处理程序
这也失败了。
org.hibernate.HibernateException:找不到配置的本地数据源 - 必须在 LocalSessionFactoryBean 上设置“dataSource”属性
Now, if 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);
}
}
新 SessionFactory 中的代理创建如下所示
SessionFactory sfProxy= (SessionFactory) Proxy.newProxyInstance(
SessionFactory.class.getClassLoader(),
new Class[] { SessionFactory.class },
new HibernateInvocationHandler(config));
并且可以返回此代理(失败)或 config.buildSessionFactory() ,它可以工作但不能解决最初的问题。
bozho 建议使用 getObject() 的替代方法。注意d)中的致命缺陷,因为buildSessionFactory不可见。
a) 如果 this.sessionfactory 为非空,则不需要代理,只需返回
b) 如果是,构建一个代理...
c) 应包含sessionfactory的私有引用,并且每次调用时检查它是否为null。如果是这样,您将构建一个新工厂,如果成功,则分配给私有引用并从现在开始返回它。
d) 现在,说明如何从 getObject() 构建该工厂。您的答案应该涉及调用 buildSessionFactory...但您不能。人们可以自己创建工厂,但最终会冒着破坏 spring 的风险(查看 buildSessionFactory 代码)