📄 sessionfactoryimpl.java
字号:
//$Id: SessionFactoryImpl.java,v 1.26.2.31 2003/11/24 03:25:30 oneovthafew Exp $package net.sf.hibernate.impl;import java.io.IOException;import java.io.InvalidObjectException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamException;import java.io.Serializable;import java.sql.Connection;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Properties;import java.util.Map.Entry;import javax.naming.NamingException;import javax.naming.Reference;import javax.naming.StringRefAddr;import javax.transaction.TransactionManager;import javax.xml.transform.Templates;import net.sf.cglib.core.KeyFactory;import net.sf.hibernate.AssertionFailure;import net.sf.hibernate.Databinder;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Interceptor;import net.sf.hibernate.MappingException;import net.sf.hibernate.QueryException;import net.sf.hibernate.Session;import net.sf.hibernate.SessionFactory;import net.sf.hibernate.cache.QueryCache;import net.sf.hibernate.cfg.Configuration;import net.sf.hibernate.cfg.Settings;import net.sf.hibernate.collection.CollectionPersister;import net.sf.hibernate.connection.ConnectionProvider;import net.sf.hibernate.dialect.Dialect;import net.sf.hibernate.engine.SessionFactoryImplementor;import net.sf.hibernate.hql.FilterTranslator;import net.sf.hibernate.hql.QueryTranslator;import net.sf.hibernate.id.IdentifierGenerator;import net.sf.hibernate.id.UUIDHexGenerator;import net.sf.hibernate.mapping.Collection;import net.sf.hibernate.mapping.NamedSQLQuery;import net.sf.hibernate.mapping.PersistentClass;import net.sf.hibernate.metadata.ClassMetadata;import net.sf.hibernate.metadata.CollectionMetadata;import net.sf.hibernate.persister.ClassPersister;import net.sf.hibernate.persister.PersisterFactory;import net.sf.hibernate.persister.Queryable;import net.sf.hibernate.tool.hbm2ddl.SchemaExport;import net.sf.hibernate.tool.hbm2ddl.SchemaUpdate;import net.sf.hibernate.transaction.TransactionFactory;import net.sf.hibernate.type.Type;import net.sf.hibernate.xml.XMLDatabinder;import org.apache.commons.collections.ReferenceMap;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import net.sf.hibernate.cache.UpdateTimestampsCache;/** * Concrete implementation of the <tt>SessionFactory</tt> interface. Has the following * responsibilites * <ul> * <li>caches configuration settings (immutably) * <li>caches "compiled" mappings ie. <tt>ClassPersister</tt>s and * <tt>CollectionPersister</tt>s (immutable) * <li>caches "compiled" queries (memory sensitive cache) * <li>manages <tt>PreparedStatement</tt>s * <li> delegates JDBC <tt>Connection</tt> management to the <tt>ConnectionProvider</tt> * <li>factory for instances of <tt>SessionImpl</tt> * </ul> * This class must appear immutable to clients, even if it does all kinds of caching * and pooling under the covers. It is crucial that the class is not only thread * safe, but also highly concurrent. Synchronization must be used extremely sparingly. * * @see net.sf.hibernate.ps.PreparedStatementCache * @see net.sf.hibernate.connection.ConnectionProvider * @see Session * @see net.sf.hibernate.hql.QueryTranslator * @see net.sf.hibernate.persister.ClassPersister * @see net.sf.hibernate.collection.CollectionPersister * @author Gavin King */public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor { private final String name; private final String uuid; private final transient Map classPersisters; private final transient Map classPersistersByName; private final transient Map classMetadata; private final transient Map collectionPersisters; private final transient Map collectionMetadata; private final transient Map namedQueries; private final transient Map namedSqlQueries; private final transient Map imports; private final transient Templates templates; private final transient Interceptor interceptor; private final transient Settings settings; private final transient Properties properties; private transient SchemaExport schemaExport; private final transient TransactionManager transactionManager; private final transient QueryCache queryCache; private final transient UpdateTimestampsCache updateTimestampsCache; private final transient Map queryCaches; private static final IdentifierGenerator UUID_GENERATOR = new UUIDHexGenerator(); private static final Log log = LogFactory.getLog(SessionFactoryImpl.class); public SessionFactoryImpl(Configuration cfg, Settings settings) throws HibernateException { log.info("building session factory"); this.properties = cfg.getProperties(); this.interceptor = cfg.getInterceptor(); this.settings = settings; if ( log.isDebugEnabled() ) log.debug( "instantiating session factory with properties: " + properties ); //Persisters: classPersisters = new HashMap(); classPersistersByName = new HashMap(); Map classMeta = new HashMap(); Iterator classes = cfg.getClassMappings(); while ( classes.hasNext() ) { PersistentClass model = (PersistentClass) classes.next(); ClassPersister cp = PersisterFactory.createClassPersister(model, this); classPersisters.put( model.getMappedClass(), cp ); classPersistersByName.put( model.getName(), cp ); classMeta.put( model.getMappedClass(), cp.getClassMetadata() ); } classMetadata = Collections.unmodifiableMap(classMeta); collectionPersisters = new HashMap(); Iterator collections = cfg.getCollectionMappings(); while ( collections.hasNext() ) { Collection map = (Collection) collections.next(); CollectionPersister persister = PersisterFactory.createCollectionPersister(cfg, map, this); collectionPersisters.put( map.getRole(), persister.getCollectionMetadata() ); } collectionMetadata = Collections.unmodifiableMap(collectionPersisters); // after *all* persisters are registered Iterator iter = classPersisters.values().iterator(); while ( iter.hasNext() ) { ( (ClassPersister) iter.next() ).postInstantiate(); } // For databinding: templates = XMLDatabinder.getOutputStyleSheetTemplates(properties); //JNDI + Serialization: name = settings.getSessionFactoryName(); try { uuid = (String) UUID_GENERATOR.generate(null, null); } catch (Exception e) { throw new AssertionFailure("Could not generate UUID"); } SessionFactoryObjectFactory.addInstance(uuid, name, this, properties); //Named Queries: // TODO: precompile and cache named queries namedQueries = new HashMap( cfg.getNamedQueries() ); namedSqlQueries = new HashMap( cfg.getNamedSQLQueries().size() ); Iterator namedIter = cfg.getNamedSQLQueries().entrySet().iterator(); while ( namedIter.hasNext() ) { Map.Entry entry = (Entry) namedIter.next(); NamedSQLQuery nsq = (NamedSQLQuery) entry.getValue(); namedSqlQueries.put( entry.getKey(), new InternalNamedSQLQuery( nsq.getQueryString(), nsq.getReturnAliases(), nsq.getReturnClasses() ) ); } imports = new HashMap( cfg.getImports() ); log.debug("instantiated session factory"); if ( settings.isAutoCreateSchema() ) new SchemaExport(cfg).create(false, true); if ( settings.isAutoUpdateSchema() ) new SchemaUpdate(cfg).execute(false); if ( settings.isAutoDropSchema() ) schemaExport = new SchemaExport(cfg); if ( settings.getTransactionManagerLookup()!=null ) { log.debug("obtaining JTA TransactionManager"); transactionManager = settings.getTransactionManagerLookup().getTransactionManager(properties); } else { transactionManager = null; } if ( settings.isQueryCacheEnabled() ) { updateTimestampsCache = new UpdateTimestampsCache( settings.getCacheProvider(), properties ); queryCache = new QueryCache( settings.getCacheProvider(), properties, updateTimestampsCache, null ); queryCaches = Collections.synchronizedMap( new HashMap() ); } else { updateTimestampsCache = null; queryCache = null; queryCaches = null; } } // Emulates constant time LRU/MRU algorithms for cache // It is better to hold strong refernces on some (LRU/MRU) queries private static final int MAX_STRONG_REF_COUNT = 128; //TODO: configurable? private final transient Object[] strongRefs = new Object[MAX_STRONG_REF_COUNT]; //strong reference to MRU queries private transient int strongRefIndex = 0; private final transient Map softQueryCache = new ReferenceMap(ReferenceMap.SOFT, ReferenceMap.SOFT) ; // both keys and values may be soft since value keeps a hard ref to the key (and there is a hard ref to MRU values) //returns generated class instance private static final QueryCacheKeyFactory QUERY_KEY_FACTORY; private static final FilterCacheKeyFactory FILTER_KEY_FACTORY; static { QUERY_KEY_FACTORY = (QueryCacheKeyFactory) KeyFactory.create(QueryCacheKeyFactory.class); FILTER_KEY_FACTORY = (FilterCacheKeyFactory) KeyFactory.create(FilterCacheKeyFactory.class); } static interface QueryCacheKeyFactory { //Will not recalculate hashKey for constant queries Object newInstance(String query, boolean scalar); } static interface FilterCacheKeyFactory { //Will not recalculate hashKey for constant queries Object newInstance(String role, String query, boolean scalar); } //TODO: this stuff can be implemented in separate class to reuse soft MRU/LRU caching private synchronized Object get(Object key) { Object result = softQueryCache.get(key); if( result != null ) { strongRefs[ ++strongRefIndex % MAX_STRONG_REF_COUNT ] = result; } return result; } private void put(Object key, Object value) { softQueryCache.put(key, value); strongRefs[ ++strongRefIndex % MAX_STRONG_REF_COUNT ] = value; } private synchronized QueryTranslator[] createQueryTranslators(String[] concreteQueryStrings, Object cacheKey) { final int length = concreteQueryStrings.length; final QueryTranslator[] queries = new QueryTranslator[length]; for ( int i=0; i<length; i++ ) queries[i] = new QueryTranslator( concreteQueryStrings[i] ); put(cacheKey, queries); return queries; } private synchronized FilterTranslator createFilterTranslator(String filterString, Object cacheKey) { final FilterTranslator filter = new FilterTranslator(filterString); put(cacheKey, filter); return filter; } public QueryTranslator[] getQuery(String queryString, boolean shallow) throws QueryException, MappingException { Object cacheKey = QUERY_KEY_FACTORY.newInstance(queryString, shallow); // have to be careful to ensure that if the JVM does out-of-order execution // then another thread can't get an uncompiled QueryTranslator from the cache // we also have to be very careful to ensure that other threads can perform // compiled queries while another query is being compiled QueryTranslator[] queries = (QueryTranslator[]) get(cacheKey); if ( queries==null ) { // a query that names an interface or unmapped class in the from clause // is actually executed as multiple queries String[] concreteQueryStrings = QueryTranslator.concreteQueries(queryString, this); queries = createQueryTranslators(concreteQueryStrings, cacheKey); } for ( int i=0; i<queries.length; i++) queries[i].compile(this, settings.getQuerySubstitutions(), shallow); // see comment above. note that QueryTranslator.compile() is synchronized return queries; } public FilterTranslator getFilter(String filterString, String collectionRole, boolean scalar) throws QueryException, MappingException { Object cacheKey = FILTER_KEY_FACTORY.newInstance(collectionRole, filterString, scalar); FilterTranslator filter = (FilterTranslator) get(cacheKey); if ( filter==null ) filter = createFilterTranslator(filterString, cacheKey); filter.compile(collectionRole, this, settings.getQuerySubstitutions(), scalar); // see comment above. note that FilterTranslator.compile() is synchronized return filter; } private Session openSession(Connection connection, boolean autoClose, long timestamp, Interceptor interceptor) { return new SessionImpl( connection, this, autoClose, timestamp, interceptor ); } public Session openSession(Connection connection, Interceptor interceptor) { return openSession( connection, false, Long.MIN_VALUE, interceptor ); } public Session openSession(Interceptor interceptor) throws HibernateException { // note that this timestamp is not correct if the connection provider // returns an older JDBC connection that was associated with a // transaction that was already begun before openSession() was called // (don't know any possible solution to this!) long timestamp = settings.getCacheProvider().nextTimestamp(); return openSession( null, true, timestamp, interceptor ); } public Session openSession(Connection connection) { return openSession(connection, interceptor); //prevents this session from adding things to cache } public Session openSession() throws HibernateException { return openSession(interceptor); } public ClassPersister getPersister(String className) throws MappingException { ClassPersister result = (ClassPersister) classPersistersByName.get(className); if (result==null) throw new MappingException( "No persister for: " + className ); return result; } public ClassPersister getPersister(Class theClass) throws MappingException { ClassPersister result = (ClassPersister) classPersisters.get(theClass); if (result==null){ throw new MappingException( "No persister for: " + theClass.getName() ); } return result; } public CollectionPersister getCollectionPersister(String role) throws MappingException {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -