spring的LocalSessionFactoryBean生成过程与hibernate的SessionFactory生成过程是高度吻合的。
为了后面源码分析,首先讲解一个接口,一个类的功能:
①、接口InitializingBean
接口的功能:这个接口专门为bean设计的,它只有一个方法。我们知道所有的bean都是由beanFactory来生成的,如果一个bean实现了该接口,在beanFactory为该bean装配好了所有的属性以后,在返回实际bean之前还会调用一次该接口的afterPropertiesSet(...)方法。其设计目的是为了实现个性化,或者是为了检查bean属性值的完整性等。
public interface InitializingBean { void afterPropertiesSet() throws Exception; }
②、类LocalSessionFactoryBuilder
显然,LocalSessionFactoryBuilder继承自org.hibernate.cfg.Configuration,那么Configuration拥有的属性,LocalSessionFactoryBuilder也具有
public class LocalSessionFactoryBuilder extends Configuration{ //... }
从LocalSessionFactoryBean源码中分析出其于hibernate的sessionFactory和configuration之间的关系:
public interface InitializingBean { void afterPropertiesSet() throws Exception; } //②、类LocalSessionFactoryBuilder //显然,LocalSessionFactoryBuilder继承自org.hibernate.cfg.Configuration,那么Configuration拥有的属性,LocalSessionFactoryBuilder也具有 public class LocalSessionFactoryBuilder extends Configuration{ //... } //现在主要分析LocalSessionFactoryBean //1、看一下几个非常重要的属性值定义 public class LocalSessionFactoryBean extends... implements InitializingBean, ...{ //数据源 private DataSource dataSource; //hibernate的配置文件Xxx.cfg.xml所在的 //位置多个可以用","隔开 private Resource[] configLocations; private String[] mappingResources; //hibernate的映射文件位置 private Resource[] mappingLocations; //hibernate的properties属性,存放了配置 //文件中解析property标签的结果 private Properties hibernateProperties; //hibernate的configuration属性 private Configuration configuration; //这个sessionfactory是hibernate的sessionFactory private SessionFactory sessionFactory; //省略其它的属性以及setter方法... //注意这个set方法,说明当只有一个配置文件 //的时候可以使用configLocation属性来配置, //最终也会被转换成configLocations public void setConfigLocation(Resource configLocation) { this.configLocations = new Resource[] {configLocation}; } @Override public void afterPropertiesSet() throws IOException { LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(this.dataSource, this.resourcePatternResolver); if (this.configLocations != null) { for (Resource resource : this.configLocations) { //sfb.configure(...)实际上也就是调用其父类 //org.hibernate.cfg.Configuration的configure(...)方法 //这里完成xxx.cfg.xml文件中property节点 //的解析,得到一个properties sfb.configure(resource.getURL()); } } //mappingResources和mappingLocations效果是一样的, //都会将资源转换成输入流,并调用sfb.addInputStream(...)方法 //sfb.addInputStream(...)最终会完成xxx.cfg.xml文件的 //非property节点解析(主要有3类:mapping、class-cache和collection-cache) //将解析结果放入到metadataSourceQueue中 if (this.mappingResources != null) { for (String mapping : this.mappingResources) { Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader()); sfb.addInputStream(mr.getInputStream()); } } if (this.mappingLocations != null) { for (Resource resource : this.mappingLocations) { sfb.addInputStream(resource.getInputStream()); } } //sfb.addProperties(...)方法会调用properties.putAll( extraProperties )方法 //说明我们可以配置一个properties对象来达到配置xxx.cfg.xml相同的效果!! //两方面的配置最终都会放入到properties对象中 if (this.hibernateProperties != null) { sfb.addProperties(this.hibernateProperties); } //省略若干其它方法... // 将sfb向上转型,LocalSessionFactoryBean中的configuration属性实际上 // 就是org.hibernate.cfg.Configuration this.configuration = sfb; //在得到configuration以后,通过它来创建一个sessionFactory, //并赋值给sessionFactory属性(LocalSessionFactoryBean的属性) //在底层会调用return super.buildSessionFactory()来的到一个 //sessionFactory,由于其父类是org.hibernate.cfg.Configuration //所以,相当于调用了configuration.buildSessionFactory()来生成 //sessionFactory,这是hibernate4.0版本之前的做法,新版本已经 //被buildSessionFactory(ServiceRegistry)所取代。 this.sessionFactory = buildSessionFactory(sfb); } }
总结spring的LocalSessionFactoryBean实际完成的工作有:
1、通过解析bean中的configLocation和mappingLocations等属性,得到一个hibernate的原生态的org.hibernate.cfg.Configuration属性
2、通过org.hibernate.cfg.Configuration生成一个hibernate原生态的org.hibernate.SessionFactory属性
3、可以在外部配置一个Properties对象,并将其配置为properties属性,可以达到与xxx.cfg.xml相同的配置效果