这个类是一个工厂类,它统一返回一个ConnectionProvider 接口供外界调用。
首先看它的三个newConnectionProvider()方法:
public static ConnectionProvider newConnectionProvider() throws HibernateException { return newConnectionProvider( Environment.getProperties() ); } public static ConnectionProvider newConnectionProvider(Properties properties) throws HibernateException { return newConnectionProvider( properties, null ); } public static ConnectionProvider newConnectionProvider(Properties properties, Map connectionProviderInjectionData) throws HibernateException { ...... ...... }
实际上最开始加载的是public static ConnectionProvider newConnectionProvider(Properties properties, Map
connectionProviderInjectionData) throws HibernateException这个方法,所以我们研究这个方法即可。
我们看看这个方法的参数,有两个,properties和connectionProviderInjectionData,一个是Properties 类型的,一
个是Map类型的,第一个参数是HIBERNATE.CFG或者HIBERNATE.PROPERTIES属性文件中的各个属性,第二个参数是用户注入
的属性值,实际上在调用这个方法的时候,connectionProviderInjectionData是为空的,也就是说,在提供了
HIBERNATE.CFG或者HIBERNATE.PROPERTIES等配置文件的时候,是不需要用户来注入数据的,除非用户自己有特殊需要,定
义自己的配置文件,则可以注入一个Map型的参数来完成配置的初始化。
该方法首先定义 connections这样一个ConnectionProvider类型的接口变量,并判断
Environment.CONNECTION_PROVIDER配置是否为空,也就是判断是否配置了连接池,所以前面提到过,真正判断是否使用连
接池是在这个类里面。若不为空,执行connections = (ConnectionProvider) ReflectHelper.classForName
(providerClass).newInstance(); 然后检测Environment.DATASOURCE参数配置,若不为空,则说明配置了数据源的连接,则connections 接口引用的是它
的实现类——DatasourceConnectionProvider。
检测Environment.URL参数配置,若不为空,说明配置了数据库连接的URL,则connections 接口引用的是它的实现类—
—DriverManagerConnectionProvider。
若用户自己扩展了ConnectionProvider 接口,也就是修改了UserSuppliedConnectionProvider类,则connections 接
口引用的是它的实现类——UserSuppliedConnectionProvider,一般情况下不需要这样做。
紧接着作者写下如下的代码:
if ( connectionProviderInjectionData != null && connectionProviderInjectionData.size() != 0 ) { //inject the data try { BeanInfo info = Introspector.getBeanInfo( connections.getClass() ); PropertyDescriptor[] descritors = info.getPropertyDescriptors(); int size = descritors.length; for (int index = 0 ; index < size ; index++) { String propertyName = descritors[index].getName(); if ( connectionProviderInjectionData.containsKey( propertyName ) ) { Method method = descritors[index].getWriteMethod(); method.invoke( connections, new Object[] { connectionProviderInjectionData.get( propertyName ) } ); } } } catch (IntrospectionException e) { throw new HibernateException("Unable to inject objects into the conenction provider", e); } catch (IllegalAccessException e) { throw new HibernateException("Unable to inject objects into the conenction provider", e); } catch (InvocationTargetException e) { throw new HibernateException("Unable to inject objects into the conenction provider", e); } } connections.configure(properties); return connections;
这段代码是不会执行的。因为在调用public static ConnectionProvider newConnectionProvider(Properties
properties) throws HibernateException 方法的时候,方法里面的return newConnectionProvider( properties, null
)第二个参数始终为空,,所以程序会向下直接执行connections.configure(properties)方法,该方法在前面介绍了,是
初始化了最基本的连接配置。但是这段代码里面使用了反射的技术,是值得关注的,我们可以看看如果用户自己扩展了
ConnectionProvider 接口,那么将如何注入自己的配置参数,去初始化最基本的连接配置。 首先通过Introspector.getBeanInfo( connections.getClass() )返回一个BeanInfo 接口,来获取有关其 bean 的方
法、属性、事件等显式信息。 PropertyDescriptor[] descritors = info.getPropertyDescriptors();通过BeanInfo 的getPropertyDescriptors()
方法来获取它的支持的可编辑属性的 PropertyDescriptor 数组。并一个个判断,注入属性的键值是否与该类中的属性同
名,若同名则通过Method method = descritors[index].getWriteMethod()来获取其属性的setter方法,通过
method.invoke( connections, new Object[] { connectionProviderInjectionData.get( propertyName ) } )来设定其
属性的值,也就达到了注入数据的目的。 HIBERNATE中使用了大量的反射技术,它使用 Java 反射机制而不是字节码增强程序来实现透明性。
以上的代码不执行,而直接执行connections.configure(properties)方法,初始化了最基本的连接配置,直接返回该 ConnectionProvider 接口。
getConnectionProperties( props )方法在前面已经介绍。
这样, org.hibernate.connection包分析完了。