LocalSessionFacotoryBean其实就是适配了Configuration对象,或者说是一个工厂的工厂,他是Configuration的工厂,生成了Configuration以后,再利用他生成了SessioFactory;
- public class LocalSessionFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
- //线程变量的DataSource
- private static final ThreadLocal configTimeDataSourceHolder = new ThreadLocal();
- //线程变量TransactionManager
- private static final ThreadLocal configTimeTransactionManagerHolder = new ThreadLocal();
- //线程变量LoBHandler
- private static final ThreadLocal configTimeLobHandlerHolder = new ThreadLocal();
- //取得当前的线程变量,每个线程对应不同的变量;
- public static DataSource getConfigTimeDataSource() {
- return (DataSource) configTimeDataSourceHolder.get();
- }
- public static TransactionManager getConfigTimeTransactionManager() {
- return (TransactionManager) configTimeTransactionManagerHolder.get();
- }
- public static LobHandler getConfigTimeLobHandler() {
- return (LobHandler) configTimeLobHandlerHolder.get();
- }
- protected final Log logger = LogFactory.getLog(getClass());
- //一下是一些Hibernate的SessionFactory的配置属性,以前我们可以在hibernate.cfg.xml中配置;
- private Class configurationClass = Configuration.class;
- private Resource[] configLocations;
- //如下是对象和数据库表对应的hbm.xml文件
- private Resource[] mappingLocations;
- private Resource[] cacheableMappingLocations;
- private Resource[] mappingJarLocations;
- private Resource[] mappingDirectoryLocations;
- //Hibernate的属性设置
- private Properties hibernateProperties;
- //数据源
- private DataSource dataSource;
- private boolean useTransactionAwareDataSource = false;
- private boolean exposeTransactionAwareSessionFactory = true;
- private TransactionManager jtaTransactionManager;
- private LobHandler lobHandler;
- private Interceptor entityInterceptor;
- private NamingStrategy namingStrategy;
- private Properties entityCacheStrategies;
- private Properties collectionCacheStrategies;
- private TypeDefinitionBean[] typeDefinitions;
- private FilterDefinition[] filterDefinitions;
- private Map eventListeners;
- private boolean schemaUpdate = false;
- private Configuration configuration;
- //该对象是FactoryBean,会用getObject返回正真的对象;
- private SessionFactory sessionFactory;
- public void setConfigurationClass(Class configurationClass) {
- if (configurationClass == null || !Configuration.class.isAssignableFrom(configurationClass)) {
- throw new IllegalArgumentException(
- "configurationClass must be assignable to [org.hibernate.cfg.Configuration]");
- }
- this.configurationClass = configurationClass;
- }
- public void setMappingJarLocations(Resource[] mappingJarLocations) {
- this.mappingJarLocations = mappingJarLocations;
- }
- public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) {
- this.mappingDirectoryLocations = mappingDirectoryLocations;
- }
- public void setHibernateProperties(Properties hibernateProperties) {
- this.hibernateProperties = hibernateProperties;
- }
- public Properties getHibernateProperties() {
- if (this.hibernateProperties == null) {
- this.hibernateProperties = new Properties();
- }
- return this.hibernateProperties;
- }
- public void setDataSource(DataSource dataSource) {
- this.dataSource = dataSource;
- }
- public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
- this.useTransactionAwareDataSource = useTransactionAwareDataSource;
- }
- public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
- this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
- }
- public void setJtaTransactionManager(TransactionManager jtaTransactionManager) {
- this.jtaTransactionManager = jtaTransactionManager;
- }
- public void setLobHandler(LobHandler lobHandler) {
- this.lobHandler = lobHandler;
- }
- public void setEntityInterceptor(Interceptor entityInterceptor) {
- this.entityInterceptor = entityInterceptor;
- }
- public void setNamingStrategy(NamingStrategy namingStrategy) {
- this.namingStrategy = namingStrategy;
- }
- =
- public void setEntityCacheStrategies(Properties entityCacheStrategies) {
- this.entityCacheStrategies = entityCacheStrategies;
- }
- =
- public void setCollectionCacheStrategies(Properties collectionCacheStrategies) {
- this.collectionCacheStrategies = collectionCacheStrategies;
- }
- public void setTypeDefinitions(TypeDefinitionBean[] typeDefinitions) {
- this.typeDefinitions = typeDefinitions;
- }
- public void setFilterDefinitions(FilterDefinition[] filterDefinitions) {
- this.filterDefinitions = filterDefinitions;
- }
- =
- public void setEventListeners(Map eventListeners) {
- this.eventListeners = eventListeners;
- }
- /**
- * Set whether to execute a schema update after SessionFactory initialization.
- * <p>For details on how to make schema update scripts work, see the Hibernate
- * documentation, as this class leverages the same schema update script support
- * in org.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool.
- * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
- * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
- */
- public void setSchemaUpdate(boolean schemaUpdate) {
- this.schemaUpdate = schemaUpdate;
- }
- /**
- * Initialize the SessionFactory for the given or the default location.
- * @throws IllegalArgumentException in case of illegal property values
- * @throws HibernateException in case of Hibernate initialization errors
- */
- //在这里开始生成一个真正的SessionFactory对象;然后利用getObjecy生成出来;
- public void afterPropertiesSet() throws IllegalArgumentException, HibernateException, IOException {
- // Create Configuration instance.
- //根据反射成成一个Configuration类;准备用他来生成SessioNFactory;
- //把接受到的configuration的属性设置给Configuration
- Configuration config = newConfiguration();
- if (this.dataSource != null) {
- // Make given DataSource available for SessionFactory configuration.
- configTimeDataSourceHolder.set(this.dataSource);
- }
- if (this.jtaTransactionManager != null) {
- // Make Spring-provided JTA TransactionManager available.
- configTimeTransactionManagerHolder.set(this.jtaTransactionManager);
- }
- if (this.lobHandler != null) {
- // Make given LobHandler available for SessionFactory configuration.
- // Do early because because mapping resource might refer to custom types.
- configTimeLobHandlerHolder.set(this.lobHandler);
- }
- try {
- if (this.jtaTransactionManager != null) {
- // Set Spring-provided JTA TransactionManager as Hibernate property.
- config.setProperty(
- Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());
- config.setProperty(
- Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName());
- }
- else {
- // Set connection release mode "on_close" as default.
- // This was the case for Hibernate 3.0; Hibernate 3.1 changed
- // it to "auto" (i.e. "after_statement" or "after_transaction").
- // However, for Spring's resource management (in particular for
- // HibernateTransactionManager), "on_close" is the better default.
- config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());
- }
- if (this.entityInterceptor != null) {
- // Set given entity interceptor at SessionFactory level.
- config.setInterceptor(this.entityInterceptor);
- }
- if (this.namingStrategy != null) {
- // Pass given naming strategy to Hibernate Configuration.
- config.setNamingStrategy(this.namingStrategy);
- }
- if (this.typeDefinitions != null) {
- // Register specified Hibernate type definitions.
- Mappings mappings = config.createMappings();
- for (int i = 0; i < this.typeDefinitions.length; i++) {
- TypeDefinitionBean typeDef = this.typeDefinitions[i];
- mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());
- }
- }
- if (this.filterDefinitions != null) {
- // Register specified Hibernate FilterDefinitions.
- for (int i = 0; i < this.filterDefinitions.length; i++) {
- config.addFilterDefinition(this.filterDefinitions[i]);
- }
- }
- if (this.configLocations != null) {
- for (int i = 0; i < this.configLocations.length; i++) {
- // Load Hibernate configuration from given location.
- config.configure(this.configLocations[i].getURL());
- }
- }
- if (this.hibernateProperties != null) {
- // Add given Hibernate properties to Configuration.
- config.addProperties(this.hibernateProperties);
- }
- if (this.dataSource != null) {
- boolean actuallyTransactionAware =
- (this.useTransactionAwareDataSource || this.dataSource instanceof TransactionAwareDataSourceProxy);
- // Set Spring-provided DataSource as Hibernate ConnectionProvider.
- config.setProperty(Environment.CONNECTION_PROVIDER,
- actuallyTransactionAware ?
- TransactionAwareDataSourceConnectionProvider.class.getName() :
- LocalDataSourceConnectionProvider.class.getName());
- }
- if (this.mappingLocations != null) {
- // Register given Hibernate mapping definitions, contained in resource files.
- for (int i = 0; i < this.mappingLocations.length; i++) {
- config.addInputStream(this.mappingLocations[i].getInputStream());
- }
- }
- if (this.cacheableMappingLocations != null) {
- // Register given cacheable Hibernate mapping definitions, read from the file system.
- for (int i = 0; i < this.cacheableMappingLocations.length; i++) {
- config.addCacheableFile(this.cacheableMappingLocations[i].getFile());
- }
- }
- if (this.mappingJarLocations != null) {
- // Register given Hibernate mapping definitions, contained in jar files.
- for (int i = 0; i < this.mappingJarLocations.length; i++) {
- Resource resource = this.mappingJarLocations[i];
- config.addJar(resource.getFile());
- }
- }
- if (this.mappingDirectoryLocations != null) {
- // Register all Hibernate mapping definitions in the given directories.
- for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {
- File file = this.mappingDirectoryLocations[i].getFile();
- if (!file.isDirectory()) {
- throw new IllegalArgumentException(
- "Mapping directory location [" + this.mappingDirectoryLocations[i] +
- "] does not denote a directory");
- }
- config.addDirectory(file);
- }
- }
- if (this.entityCacheStrategies != null) {
- // Register cache strategies for mapped entities.
- for (Enumeration classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {
- String className = (String) classNames.nextElement();
- config.setCacheConcurrencyStrategy(className, this.entityCacheStrategies.getProperty(className));
- }
- }
- if (this.collectionCacheStrategies != null) {
- // Register cache strategies for mapped collections.
- for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {
- String collRole = (String) collRoles.nextElement();
- config.setCollectionCacheConcurrencyStrategy(
- collRole, this.collectionCacheStrategies.getProperty(collRole));
- }
- }
- //增加时间处理器;
- if (this.eventListeners != null) {
- // Register specified Hibernate event listeners.
- for (Iterator it = this.eventListeners.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- String listenerType = (String) entry.getKey();
- Object listenerObject = entry.getValue();
- config.setListener(listenerType, listenerObject);
- }
- }
- //注意,这里是一个默认实现,其实我们可以叫钩子,他能够在Configuration生成之际是对其进行拦截处理;
- postProcessConfiguration(config);
- // Build SessionFactory instance.
- logger.info("Building new Hibernate SessionFactory");
- this.configuration = config;
- SessionFactory sf = newSessionFactory(config);
- //是否生成代理sessionFactoty对象,这个代理对象不同的是,他不能调用close方法,无用;
- if (this.exposeTransactionAwareSessionFactory) {
- this.sessionFactory = getTransactionAwareSessionFactoryProxy(sf);
- }
- else {
- this.sessionFactory = sf;
- }
- // Execute schema update if requested.
- if (this.schemaUpdate) {
- updateDatabaseSchema();
- }
- }
- finally {
- if (this.dataSource != null) {
- // Reset DataSource holder.
- configTimeDataSourceHolder.set(null);
- }
- if (this.jtaTransactionManager != null) {
- // Reset TransactionManager holder.
- configTimeTransactionManagerHolder.set(null);
- }
- if (this.lobHandler != null) {
- // Reset LobHandler holder.
- configTimeLobHandlerHolder.set(null);
- }
- }
- }
- /**
- * Subclasses can override this method to perform custom initialization
- * of the Configuration instance used for SessionFactory creation.
- * The properties of this LocalSessionFactoryBean will be applied to
- * the Configuration object that gets returned here.
- * <p>The default implementation creates a new Configuration instance.
- * A custom implementation could prepare the instance in a specific way,
- * or use a custom Configuration subclass.
- * @return the Configuration instance
- * @throws HibernateException in case of Hibernate initialization errors
- * @see org.hibernate.cfg.Configuration#Configuration()
- */
- //以下是Configuration生成SessionFactory的典型做法;
- protected Configuration newConfiguration() throws HibernateException {
- return (Configuration) BeanUtils.instantiateClass(this.configurationClass);
- }
- /**
- * To be implemented by subclasses that want to to perform custom
- * post-processing of the Configuration object after this FactoryBean
- * performed its default initialization.
- * @param config the current Configuration object
- * @throws HibernateException in case of Hibernate initialization errors
- */
- protected void postProcessConfiguration(Configuration config) throws HibernateException {
- }
- /**
- * Subclasses can override this method to perform custom initialization
- * of the SessionFactory instance, creating it via the given Configuration
- * object that got prepared by this LocalSessionFactoryBean.
- * <p>The default implementation invokes Configuration's buildSessionFactory.
- * A custom implementation could prepare the instance in a specific way,
- * or use a custom SessionFactoryImpl subclass.
- * @param config Configuration prepared by this LocalSessionFactoryBean
- * @return the SessionFactory instance
- * @throws HibernateException in case of Hibernate initialization errors
- * @see org.hibernate.cfg.Configuration#buildSessionFactory
- */
- protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
- return config.buildSessionFactory();
- }
- /**
- * Wrap the given SessionFactory with a proxy that delegates every method call
- * to it but delegates <code>getCurrentSession</code> calls to SessionFactoryUtils,
- * for participating in Spring-managed transactions.
- * @param target the original SessionFactory to wrap
- * @return the wrapped SessionFactory
- * @see org.hibernate.SessionFactory#getCurrentSession()
- * @see SessionFactoryUtils#doGetSession(org.hibernate.SessionFactory, boolean)
- */
- protected SessionFactory getTransactionAwareSessionFactoryProxy(SessionFactory target) {
- Class sfInterface = SessionFactory.class;
- if (target instanceof SessionFactoryImplementor) {
- sfInterface = SessionFactoryImplementor.class;
- }
- return (SessionFactory) Proxy.newProxyInstance(sfInterface.getClassLoader(),
- new Class[] {sfInterface}, new TransactionAwareInvocationHandler(target));
- }
- =
- public void dropDatabaseSchema() throws DataAccessException {
- logger.info("Dropping database schema for Hibernate SessionFactory");
- HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
- hibernateTemplate.execute(
- new HibernateCallback() {
- public Object doInHibernate(Session session) throws HibernateException, SQLException {
- Connection con = session.connection();
- Dialect dialect = Dialect.getDialect(configuration.getProperties());
- String[] sql = configuration.generateDropSchemaScript(dialect);
- executeSchemaScript(con, sql);
- return null;
- }
- }
- );
- }
- /**
- * Execute schema creation script, determined by the Configuration object
- * used for creating the SessionFactory. A replacement for Hibernate's
- * SchemaExport class, to be invoked on application setup.
- * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
- * SessionFactory to be able to invoke this method, e.g. via
- * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
- * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
- * connection to perform the script.
- * @throws DataAccessException in case of script execution errors
- * @see org.hibernate.cfg.Configuration#generateSchemaCreationScript
- * @see org.hibernate.tool.hbm2ddl.SchemaExport#create
- */
- public void createDatabaseSchema() throws DataAccessException {
- logger.info("Creating database schema for Hibernate SessionFactory");
- HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
- hibernateTemplate.execute(
- new HibernateCallback() {
- public Object doInHibernate(Session session) throws HibernateException, SQLException {
- Connection con = session.connection();
- Dialect dialect = Dialect.getDialect(configuration.getProperties());
- String[] sql = configuration.generateSchemaCreationScript(dialect);
- executeSchemaScript(con, sql);
- return null;
- }
- }
- );
- }
- /**
- * Execute schema update script, determined by the Configuration object
- * used for creating the SessionFactory. A replacement for Hibernate's
- * SchemaUpdate class, for automatically executing schema update scripts
- * on application startup. Can also be invoked manually.
- * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
- * SessionFactory to be able to invoke this method, e.g. via
- * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
- * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
- * connection to perform the script.
- * @throws DataAccessException in case of script execution errors
- * @see #setSchemaUpdate
- * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
- * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
- */
- public void updateDatabaseSchema() throws DataAccessException {
- logger.info("Updating database schema for Hibernate SessionFactory");
- HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
- hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER);
- hibernateTemplate.execute(
- new HibernateCallback() {
- public Object doInHibernate(Session session) throws HibernateException, SQLException {
- Connection con = session.connection();
- Dialect dialect = Dialect.getDialect(configuration.getProperties());
- DatabaseMetadata metadata = new DatabaseMetadata(con, dialect);
- String[] sql = configuration.generateSchemaUpdateScript(dialect, metadata);
- executeSchemaScript(con, sql);
- return null;
- }
- }
- );
- }
- protected void executeSchemaScript(Connection con, String[] sql) throws SQLException {
- if (sql != null && sql.length > 0) {
- boolean oldAutoCommit = con.getAutoCommit();
- if (!oldAutoCommit) {
- con.setAutoCommit(true);
- }
- try {
- Statement stmt = con.createStatement();
- try {
- for (int i = 0; i < sql.length; i++) {
- executeSchemaStatement(stmt, sql[i]);
- }
- }
- finally {
- JdbcUtils.closeStatement(stmt);
- }
- }
- finally {
- if (!oldAutoCommit) {
- con.setAutoCommit(false);
- }
- }
- }
- }
- protected void executeSchemaStatement(Statement stmt, String sql) throws SQLException {
- if (logger.isDebugEnabled()) {
- logger.debug("Executing schema statement: " + sql);
- }
- try {
- stmt.executeUpdate(sql);
- }
- catch (SQLException ex) {
- if (logger.isWarnEnabled()) {
- logger.warn("Unsuccessful schema statement: " + sql, ex);
- }
- }
- }
- /**
- * Return the Configuration object used to build the SessionFactory.
- * Allows access to configuration metadata stored there (rarely needed).
- */
- public Configuration getConfiguration() {
- return this.configuration;
- }
- /**
- * Return the singleton SessionFactory.
- */
- public Object getObject() {
- return this.sessionFactory;
- }
- public Class getObjectType() {
- return (this.sessionFactory != null) ? this.sessionFactory.getClass() : SessionFactory.class;
- }
- public boolean isSingleton() {
- return true;
- }
- /**
- * Close the SessionFactory on bean factory shutdown.
- */
- public void destroy() throws HibernateException {
- logger.info("Closing Hibernate SessionFactory");
- if (this.dataSource != null) {
- // Make given DataSource available for potential SchemaExport,
- // which unfortunately reinstantiates a ConnectionProvider.
- configTimeDataSourceHolder.set(this.dataSource);
- }
- try {
- this.sessionFactory.close();
- }
- finally {
- if (this.dataSource != null) {
- // Reset DataSource holder.
- configTimeDataSourceHolder.set(null);
- }
- }
- }
- /**
- * Invocation handler that delegates <code>getCurrentSession()</code> calls
- * to SessionFactoryUtils, for being aware of thread-bound transactions.
- */
- private static class TransactionAwareInvocationHandler implements InvocationHandler {
- private final SessionFactory target;
- public TransactionAwareInvocationHandler(SessionFactory target) {
- this.target = target;
- }
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // Invocation on SessionFactory/SessionFactoryImplementor interface coming in...
- if (method.getName().equals("getCurrentSession")) {
- // Handle getCurrentSession method: return transactional Session, if any.
- try {
- return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);
- }
- catch (IllegalStateException ex) {
- throw new HibernateException(ex.getMessage());
- }
- }
- else if (method.getName().equals("equals")) {
- // Only consider equal when proxies are identical.
- return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
- }
- else if (method.getName().equals("hashCode")) {
- // Use hashCode of SessionFactory proxy.
- return new Integer(hashCode());
- }
- // Invoke method on target SessionFactory.
- try {
- return method.invoke(this.target, args);
- }
- catch (InvocationTargetException ex) {
- throw ex.getTargetException();
- }
- }
- }
- }