001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.orm.hibernate3; 018 019import javax.sql.DataSource; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023import org.hibernate.HibernateException; 024import org.hibernate.SessionFactory; 025 026import org.springframework.beans.factory.DisposableBean; 027import org.springframework.beans.factory.FactoryBean; 028import org.springframework.beans.factory.InitializingBean; 029 030/** 031 * Abstract {@link org.springframework.beans.factory.FactoryBean} that creates 032 * a Hibernate {@link org.hibernate.SessionFactory} within a Spring application 033 * context, providing general infrastructure not related to Hibernate's 034 * specific configuration API. 035 * 036 * <p>This class implements the 037 * {@link org.springframework.dao.support.PersistenceExceptionTranslator} 038 * interface, as autodetected by Spring's 039 * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}, 040 * for AOP-based translation of native exceptions to Spring DataAccessExceptions. 041 * Hence, the presence of e.g. LocalSessionFactoryBean automatically enables 042 * a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions. 043 * 044 * <p>This class mainly serves as common base class for {@link LocalSessionFactoryBean}. 045 * For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc. 046 * 047 * @author Juergen Hoeller 048 * @since 2.0 049 * @see #setExposeTransactionAwareSessionFactory 050 * @see org.hibernate.SessionFactory#getCurrentSession() 051 * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor 052 * @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x 053 */ 054@Deprecated 055public abstract class AbstractSessionFactoryBean extends HibernateExceptionTranslator 056 implements FactoryBean<SessionFactory>, InitializingBean, DisposableBean { 057 058 /** Logger available to subclasses */ 059 protected final Log logger = LogFactory.getLog(getClass()); 060 061 private DataSource dataSource; 062 063 private boolean useTransactionAwareDataSource = false; 064 065 private boolean exposeTransactionAwareSessionFactory = true; 066 067 private SessionFactory sessionFactory; 068 069 070 /** 071 * Set the DataSource to be used by the SessionFactory. 072 * If set, this will override corresponding settings in Hibernate properties. 073 * <p>If this is set, the Hibernate settings should not define 074 * a connection provider to avoid meaningless double configuration. 075 * <p>If using HibernateTransactionManager as transaction strategy, consider 076 * proxying your target DataSource with a LazyConnectionDataSourceProxy. 077 * This defers fetching of an actual JDBC Connection until the first JDBC 078 * Statement gets executed, even within JDBC transactions (as performed by 079 * HibernateTransactionManager). Such lazy fetching is particularly beneficial 080 * for read-only operations, in particular if the chances of resolving the 081 * result in the second-level cache are high. 082 * <p>As JTA and transactional JNDI DataSources already provide lazy enlistment 083 * of JDBC Connections, LazyConnectionDataSourceProxy does not add value with 084 * JTA (i.e. Spring's JtaTransactionManager) as transaction strategy. 085 * @see #setUseTransactionAwareDataSource 086 * @see HibernateTransactionManager 087 * @see org.springframework.transaction.jta.JtaTransactionManager 088 * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy 089 */ 090 public void setDataSource(DataSource dataSource) { 091 this.dataSource = dataSource; 092 } 093 094 /** 095 * Return the DataSource to be used by the SessionFactory. 096 */ 097 public DataSource getDataSource() { 098 return this.dataSource; 099 } 100 101 /** 102 * Set whether to use a transaction-aware DataSource for the SessionFactory, 103 * i.e. whether to automatically wrap the passed-in DataSource with Spring's 104 * TransactionAwareDataSourceProxy. 105 * <p>Default is "false": LocalSessionFactoryBean is usually used with Spring's 106 * HibernateTransactionManager or JtaTransactionManager, both of which work nicely 107 * on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are 108 * fully managed by the Hibernate/JTA transaction infrastructure in such a scenario. 109 * <p>If you switch this flag to "true", Spring's Hibernate access will be able to 110 * <i>participate in JDBC-based transactions managed outside of Hibernate</i> 111 * (for example, by Spring's DataSourceTransactionManager). This can be convenient 112 * if you need a different local transaction strategy for another O/R mapping tool, 113 * for example, but still want Hibernate access to join into those transactions. 114 * <p>A further benefit of this option is that <i>plain Sessions opened directly 115 * via the SessionFactory</i>, outside of Spring's Hibernate support, will still 116 * participate in active Spring-managed transactions. However, consider using 117 * Hibernate's {@code getCurrentSession()} method instead (see javadoc of 118 * "exposeTransactionAwareSessionFactory" property). 119 * <p><b>WARNING:</b> When using a transaction-aware JDBC DataSource in combination 120 * with OpenSessionInViewFilter/Interceptor, whether participating in JTA or 121 * external JDBC-based transactions, it is strongly recommended to set Hibernate's 122 * Connection release mode to "after_transaction" or "after_statement", which 123 * guarantees proper Connection handling in such a scenario. In contrast to that, 124 * HibernateTransactionManager generally requires release mode "on_close". 125 * <p>Note: If you want to use Hibernate's Connection release mode "after_statement" 126 * with a DataSource specified on this LocalSessionFactoryBean (for example, a 127 * JTA-aware DataSource fetched from JNDI), switch this setting to "true". 128 * Otherwise, the ConnectionProvider used underneath will vote against aggressive 129 * release and thus silently switch to release mode "after_transaction". 130 * @see #setDataSource 131 * @see #setExposeTransactionAwareSessionFactory 132 * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy 133 * @see org.springframework.jdbc.datasource.DataSourceTransactionManager 134 * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter 135 * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor 136 * @see HibernateTransactionManager 137 * @see org.springframework.transaction.jta.JtaTransactionManager 138 */ 139 public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) { 140 this.useTransactionAwareDataSource = useTransactionAwareDataSource; 141 } 142 143 /** 144 * Return whether to use a transaction-aware DataSource for the SessionFactory. 145 */ 146 protected boolean isUseTransactionAwareDataSource() { 147 return this.useTransactionAwareDataSource; 148 } 149 150 /** 151 * Set whether to expose a transaction-aware current Session from the 152 * SessionFactory's {@code getCurrentSession()} method, returning the 153 * Session that's associated with the current Spring-managed transaction, if any. 154 * <p>Default is "true", letting data access code work with the plain 155 * Hibernate SessionFactory and its {@code getCurrentSession()} method, 156 * while still being able to participate in current Spring-managed transactions: 157 * with any transaction management strategy, either local or JTA / EJB CMT, 158 * and any transaction synchronization mechanism, either Spring or JTA. 159 * Furthermore, {@code getCurrentSession()} will also seamlessly work with 160 * a request-scoped Session managed by OpenSessionInViewFilter/Interceptor. 161 * <p>Turn this flag off to expose the plain Hibernate SessionFactory with 162 * Hibernate's default {@code getCurrentSession()} behavior, supporting 163 * plain JTA synchronization only. Alternatively, simply override the 164 * corresponding Hibernate property "hibernate.current_session_context_class". 165 * @see SpringSessionContext 166 * @see org.hibernate.SessionFactory#getCurrentSession() 167 * @see org.springframework.transaction.jta.JtaTransactionManager 168 * @see HibernateTransactionManager 169 * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter 170 * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor 171 */ 172 public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) { 173 this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory; 174 } 175 176 /** 177 * Return whether to expose a transaction-aware proxy for the SessionFactory. 178 */ 179 protected boolean isExposeTransactionAwareSessionFactory() { 180 return this.exposeTransactionAwareSessionFactory; 181 } 182 183 184 /** 185 * Build and expose the SessionFactory. 186 * @see #buildSessionFactory() 187 * @see #wrapSessionFactoryIfNecessary 188 */ 189 @Override 190 public void afterPropertiesSet() throws Exception { 191 SessionFactory rawSf = buildSessionFactory(); 192 this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf); 193 afterSessionFactoryCreation(); 194 } 195 196 /** 197 * Wrap the given SessionFactory with a proxy, if demanded. 198 * <p>The default implementation simply returns the given SessionFactory as-is. 199 * Subclasses may override this to implement transaction awareness through 200 * a SessionFactory proxy, for example. 201 * @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()} 202 * @return the SessionFactory reference to expose 203 * @see #buildSessionFactory() 204 */ 205 protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) { 206 return rawSf; 207 } 208 209 /** 210 * Return the exposed SessionFactory. 211 * Will throw an exception if not initialized yet. 212 * @return the SessionFactory (never {@code null}) 213 * @throws IllegalStateException if the SessionFactory has not been initialized yet 214 */ 215 protected final SessionFactory getSessionFactory() { 216 if (this.sessionFactory == null) { 217 throw new IllegalStateException("SessionFactory not initialized yet"); 218 } 219 return this.sessionFactory; 220 } 221 222 /** 223 * Close the SessionFactory on bean factory shutdown. 224 */ 225 @Override 226 public void destroy() throws HibernateException { 227 logger.info("Closing Hibernate SessionFactory"); 228 try { 229 beforeSessionFactoryDestruction(); 230 } 231 finally { 232 this.sessionFactory.close(); 233 } 234 } 235 236 237 /** 238 * Return the singleton SessionFactory. 239 */ 240 @Override 241 public SessionFactory getObject() { 242 return this.sessionFactory; 243 } 244 245 @Override 246 public Class<? extends SessionFactory> getObjectType() { 247 return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class); 248 } 249 250 @Override 251 public boolean isSingleton() { 252 return true; 253 } 254 255 256 /** 257 * Build the underlying Hibernate SessionFactory. 258 * @return the raw SessionFactory (potentially to be wrapped with a 259 * transaction-aware proxy before it is exposed to the application) 260 * @throws Exception in case of initialization failure 261 */ 262 protected abstract SessionFactory buildSessionFactory() throws Exception; 263 264 /** 265 * Hook that allows post-processing after the SessionFactory has been 266 * successfully created. The SessionFactory is already available through 267 * {@code getSessionFactory()} at this point. 268 * <p>This implementation is empty. 269 * @throws Exception in case of initialization failure 270 * @see #getSessionFactory() 271 */ 272 protected void afterSessionFactoryCreation() throws Exception { 273 } 274 275 /** 276 * Hook that allows shutdown processing before the SessionFactory 277 * will be closed. The SessionFactory is still available through 278 * {@code getSessionFactory()} at this point. 279 * <p>This implementation is empty. 280 * @see #getSessionFactory() 281 */ 282 protected void beforeSessionFactoryDestruction() { 283 } 284 285}