http://cuishen.iteye.com/blog/430735
大家平日使用spring + hibernate做項目的時候大概都接觸過下面的spring配置代碼:
下面是使用普通的jdbc驅動獲得DataSource的配置
Xml代碼 ?
< bean ?id ="dataSource" ?class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > ??????< property ?name ="driverClassName" > < value > oracle.jdbc.OracleDriver</ value > </ property > ?? ????< property ?name ="url" > < value > jdbc:oracle:thin:@caij-b815c8aab6:1521:cui</ value > </ property > ?? ????< property ?name ="username" > < value > cuishen</ value > </ property > ?? ????< property ?name ="password" > < value > cuishen</ value > </ property > ?? </ bean > ??< bean ?id ="sessionFactory" ?class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" > ??????< property ?name ="mappingResources" > < list > ?? ?????????< value > com/cuishen/testDao/pojo/Test.hbm.xml</ value > ?? ????</ list > </ property > ?? ????< property ?name ="hibernateProperties" > < props > ?? ????????< prop ?key ="dialect" > org.hibernate.dialect.Oracle9Dialect</ prop > ?? ????????< prop ?key ="connection.autocommit" > true</ prop > ?? ????</ props > </ property > ?? ????< property ?name ="dataSource" > < ref ?local ="dataSource" /> </ property > ?? </ bean > ??< bean ?id ="txManager" ?class ="org.springframework.orm.hibernate3.HibernateTransactionManager" > ??????< property ?name ="sessionFactory" > < ref ?local ="sessionFactory" /> </ property > ?? </ bean > ??< bean ?id ="dao" ?class ="com.conserv.dao.impl.HibernateDaoImpl" ?init-method ="init" ?destroy-method ="destroy" > ??????< property ?name ="transactionManager" > < ref ?local ="txManager" /> </ property > ?? ????< property ?name ="dialect" > < value > Oracle9</ value > </ property > ?? </ bean > ??
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName"><value>oracle.jdbc.OracleDriver</value></property><property name="url"><value>jdbc:oracle:thin:@caij-b815c8aab6:1521:cui</value></property><property name="username"><value>cuishen</value></property><property name="password"><value>cuishen</value></property></bean><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><property name="mappingResources"><list><value>com/cuishen/testDao/pojo/Test.hbm.xml</value></list></property><property name="hibernateProperties"><props><prop key="dialect">org.hibernate.dialect.Oracle9Dialect</prop><prop key="connection.autocommit">true</prop></props></property><property name="dataSource"><ref local="dataSource"/></property></bean><bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory"><ref local="sessionFactory"/></property></bean><bean id="dao" class="com.conserv.dao.impl.HibernateDaoImpl" init-method="init" destroy-method="destroy"><property name="transactionManager"><ref local="txManager"/></property><property name="dialect"><value>Oracle9</value></property></bean>
下面是通過JNDI獲得的DataSource的配置,只要將上面的id為"dataSource"的bean換成下面的配置就行了
Xml代碼 ?
< bean ?id ="dataSource" ?class ="org.springframework.jndi.JndiObjectFactoryBean" > ??? ??;property?name ="jndiName" ?value ="cs" ?/> ??? ?? </ bean > ??
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="cs" /> </bean>
配置很簡單,使用也非常方便,spring毫不挑食,不管是jdbc版的DataSource也好,是JNDI版的也好,它都能接受,那這個兼容性是怎么做到的呢??現在從源代碼入手來一探究竟:
1. 先看看jdbc版的DataSource - org.springframework.jdbc.datasource.DriverManagerDataSource
Java代碼 ?
public ?class ?DriverManagerDataSource?extends ?AbstractDataSource??
public class DriverManagerDataSource extends AbstractDataSource
再看看這個AbstractDataSource:
Java代碼 ?
public ?abstract ?class ?AbstractDataSource?implements ?javax.sql.DataSource??
public abstract class AbstractDataSource implements javax.sql.DataSource
哈哈,原來DriverManagerDataSource是javax.sql.DataSource的實現類,那做為bean注入給sessionFactory真是無可厚非
我們再看看它內部的實現細節
Java代碼 ?
return ?DriverManager.getConnection(url,?props);??
return DriverManager.getConnection(url, props);
哈哈,這代碼是不是再熟悉也不過啦?原來DriverManagerDataSource實現了javax.sql.DataSource接口,本質是對jdbc連接數據庫的簡單封裝
2. 接下來看看JNDI版的DataSource - org.springframework.jndi.JndiObjectFactoryBean
Java代碼 ?
public ?class ?JndiObjectFactoryBean?extends ?JndiObjectLocator?implements ?FactoryBean??
public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryBean
追溯JndiObjectFactoryBean的父類和實現的接口以及父類的父類,都和javax.sql.DataSource接口八竿子打不著,沒有一點點淵源,oh,my God! 這怎么可能!?完全不相干的對象怎么能夠被注入?這完全有悖java的精神!但事實擺在眼前,測試是完全通過的!靜下心來,我注意到了JndiObjectFactoryBean實現了FactoryBean接口,一直以來腦子里對FactoryBean模式感到有點模糊,不能完全領會其本質,難道真的是這里面有文章??好,借此機會,好好研究下FactoryBean接口,下面是org.springframework.beans.factory.FactoryBean源代碼里一段注釋:
Java代碼 ?
? ? ? ? ? ? ? ? ? ??
/*** Interface to be implemented by objects used within a BeanFactory* that are themselves factories. If a bean implements this interface,* it is used as a factory, not directly as a bean.** <p><b>NB: A bean that implements this interface cannot be used* as a normal bean.</b> A FactoryBean is defined in a bean style,* but the object exposed for bean references is always the object* that it creates.*/
翻譯過來是說:所有實現FactoryBean接口的類都被當作工廠來使用,而不是簡單的直接當作bean來使用,FactoryBean實現類里定義了要生產的對象,并且由FactoryBean實現類來造該對象的實例,看到這里聰明的你大概已經能猜出個八九不離十了吧
我們回過頭來看看JndiObjectFactoryBean的實現細節
Java代碼 ?
private ?Object?jndiObject; ??? ? ? ?? public ?void ?afterPropertiesSet()?throws ?IllegalArgumentException,?NamingException?{ ??????super .afterPropertiesSet(); ?? ?? ????if ?(this .proxyInterface?!=?null )?{ ?? ????????if ?(this .defaultObject?!=?null )?{ ?? ????????????throw ?new ?IllegalArgumentException( ?? ????????????????????"'defaultObject'?is?not?supported?in?combination?with?'proxyInterface'" ); ?? ????????} ?? ?????????? ????????this .jndiObject?=?JndiObjectProxyFactory.createJndiObjectProxy(this ); ?? ????} ?? ?? ????else ?{ ?? ????????if ?(!this .lookupOnStartup?||?!this .cache)?{ ?? ????????????throw ?new ?IllegalArgumentException( ?? ????????????????"Cannot?deactivate?'lookupOnStartup'?or?'cache'?without?specifying?a?'proxyInterface'" ); ?? ????????} ?? ????????if ?(this .defaultObject?!=?null ?&&?getExpectedType()?!=?null ?&& ?? ????????????????!getExpectedType().isInstance(this .defaultObject))?{ ?? ????????????throw ?new ?IllegalArgumentException("Default?object?[" ?+?this .defaultObject?+ ?? ????????????????????"]?of?type?[" ?+?this .defaultObject.getClass().getName()?+ ?? ????????????????????"]?is?not?of?expected?type?[" ?+?getExpectedType().getName()?+?"]" ); ?? ????????} ?? ???????? ?? ????????this .jndiObject?=?lookupWithFallback(); ?? ????} ?? } ?? ? ? ? ?? public ?Object?getObject()?{ ??????return ?this .jndiObject; ?? } ?? ?? public ?Class?getObjectType()?{ ??????if ?(this .proxyInterface?!=?null )?{ ?? ????????return ?this .proxyInterface; ?? ????} ?? ????else ?if ?(this .jndiObject?!=?null )?{ ?? ????????return ?this .jndiObject.getClass(); ?? ????} ?? ????else ?{ ?? ????????return ?getExpectedType(); ?? ????} ?? }??
private Object jndiObject;/*** Look up the JNDI object and store it.* 廣義上說是造對象的過程,就本例而言,是通過JNDI獲得DataSource對象*/public void afterPropertiesSet() throws IllegalArgumentException, NamingException {super.afterPropertiesSet();if (this.proxyInterface != null) {if (this.defaultObject != null) {throw new IllegalArgumentException("'defaultObject' is not supported in combination with 'proxyInterface'");}// We need a proxy and a JndiObjectTargetSource.this.jndiObject = JndiObjectProxyFactory.createJndiObjectProxy(this);}else {if (!this.lookupOnStartup || !this.cache) {throw new IllegalArgumentException("Cannot deactivate 'lookupOnStartup' or 'cache' without specifying a 'proxyInterface'");}if (this.defaultObject != null && getExpectedType() != null &&!getExpectedType().isInstance(this.defaultObject)) {throw new IllegalArgumentException("Default object [" + this.defaultObject +"] of type [" + this.defaultObject.getClass().getName() +"] is not of expected type [" + getExpectedType().getName() + "]");}// Locate specified JNDI object.this.jndiObject = lookupWithFallback();}}/*** Return the singleton JNDI object.* 返回JNDI對象(DataSource對象)*/public Object getObject() {return this.jndiObject;}public Class getObjectType() {if (this.proxyInterface != null) {return this.proxyInterface;}else if (this.jndiObject != null) {return this.jndiObject.getClass();}else {return getExpectedType();}}
現在揭曉謎底:很簡單,對于JndiObjectFactoryBean對象,spring IOC容器啟動時確實造了它的對象,只不過這時是工廠本身,spring會自動調用工廠里的afterPropertiesSet()方法去造真正需要的bean,然后調用getObject()和getObjectType()方法返回已造好的對象和類型,再將其準確的注入依賴它的其他bean里面,所以并沒有違背java的精神! 有興趣也可以看看org.springframework.orm.hibernate3.LocalSessionFactoryBean,它也實現了FactoryBean接口,內部實現如出一轍,只不過它擔負的重任不是造JNDI object,而是要造SessionFactory對象
?
?
?
?
?
?
?
=========http://blog.csdn.net/turkeyzhou/article/details/3139258
在此之前,我已經接觸到了DataSource和JTA事務了,我們都應用到了JNDI技術;在Spring中提供了JNDI技術的整合支持,JNDI如何使用,我就不累贅了,具體我們來看一下整合的源代碼: 代碼類結構: 我們從上而下進行分析; 首先是: JndiTemplate: jndiTemplate提供了對JNDI服務器的vjndi對象的綁定,查詢,撤銷綁定和重新綁定,從一定意義上來說他跟JdbcTemplate等是同意概念的類,直接與資源管理器進行交互,并且同樣的是采用的回調機制,我們可以看見其依賴了JndiCallbake接口: 其對綁定,差性能,撤銷,重新綁定的實現的源代碼如下:
public ?Object?execute(JndiCallback?contextCallback)?throws?NamingException?{????????Context?ctx?=?createInitialContext(); ????????try ?{ ????????????return ?contextCallback.doInContext(ctx); ????????} ????????finally ?{ ????????????try ?{ ????????????????ctx.close(); ????????????} ????????????catch ?(NamingException?ex)?{ ????????????????logger.debug("Could?not?close?JNDI?InitialContext" ,?ex); ????????????} ????????} ????}
????protected ?Context?createInitialContext()?throws?NamingException?{ ????????return ?new ?InitialContext(getEnvironment()); ????}
這段代碼生成了上下文,進而把上下文傳遞給了JndiCallBack,在這個接口的回調方法,我們直接使用context對資源管理器進行curd交互; 綁定對象:
public ?Object?lookup(final?String?name)?throws?NamingException?{????????if ?(logger.isDebugEnabled())?{ ????????????logger.debug("Looking?up?JNDI?object?with?name?[" ?+?name?+?"]" ); ????????} ????????return ?execute(new ?JndiCallback()?{ ????????????public ?Object?doInContext(Context?ctx)?throws?NamingException?{ ????????????????Object?located?=?ctx.lookup(name); ????????????????if ?(located?==?null )?{ ????????????????????throw ?new ?NameNotFoundException( ????????????????????????????"JNDI?object?with?[" ?+?name?+?"]?not?found:?JNDI?implementation? returned?null "); ????????????????} ????????????????return ?located; ????????????} ????????}); ????}
????public ?void ?bind(final?String?name,?final?Object?object )?throws?NamingException?{ ????????if ?(logger.isDebugEnabled())?{ ????????????logger.debug("Binding?JNDI?object?with?name?[" ?+?name?+?"]" ); ????????} ????????execute(new ?JndiCallback()?{ ????????????public ?Object?doInContext(Context?ctx)?throws?NamingException?{ ????????????????ctx.bind(name,?object ); ????????????????return ?null ; ????????????} ????????}); ????}
重新綁定:
public ?void ?rebind(final?String?name,?final?Object?object )?throws?NamingException?{????????if ?(logger.isDebugEnabled())?{ ????????????logger.debug("Rebinding?JNDI?object?with?name?[" ?+?name?+?"]" ); ????????} ????????execute(new ?JndiCallback()?{ ????????????public ?Object?doInContext(Context?ctx)?throws?NamingException?{ ????????????????ctx.rebind(name,?object ); ????????????????return ?null ; ????????????} ????????}); ????}
撤銷綁定:
public ?void ?unbind(final?String?name)?throws?NamingException?{????????if ?(logger.isDebugEnabled())?{ ????????????logger.debug("Unbinding?JNDI?object?with?name?[" ?+?name?+?"]" ); ????????} ????????execute(new ?JndiCallback()?{ ????????????public ?Object?doInContext(Context?ctx)?throws?NamingException?{ ????????????????ctx.unbind(name); ????????????????return ?null ; ????????????} ????????}); ????} ???? }
通過JndiTemplate,我們實現了底層訪問代碼;形成了具體實現層;與上層開來; JndiAccessor:只是單純的對JndiTemplate進行了包裝,隔離了底層的實現細節; JndiLocatorSupport的主要擴展的功能是,如果我們在配置JndiObjectFactoryBean的時候,配置了參數:resourceRef為true的話,那么就會如果我們查找的資源中間不包含:或者java:等前綴,我們會自動的會該路徑加上java:comp/env,主要是匹配在j2ee容器里面的jndi資源的查找;
????protected ?String?convertJndiName(String?jndiName)?{ ???????? ????????if ?(isResourceRef()?&&?!jndiName.startsWith(CONTAINER_PREFIX)?&&?jndiName.indexOf(':' )?==?-1)?{ ????????????jndiName?=?CONTAINER_PREFIX?+?jndiName; ????????} ????????return ?jndiName; ????}
最后,我們再來看一下: 在JndiObjectFactoryBean我們實際上得到的是: ?? jndiObject : 初始化生成如下:
public ?void ?afterPropertiesSet()?throws?IllegalArgumentException,?NamingException?{????????super.afterPropertiesSet(); ????????if ?(this .proxyInterface?!=?null )?{ ????????????if ?(this .defaultObject?!=?null )?{ ????????????????throw ?new ?IllegalArgumentException( ????????????????????????"'defaultObject'?is?not?supported?in?combination?with?'proxyInterface'" ); ????????????} ???????????? ????????????this .jndiObject?=?JndiObjectProxyFactory.createJndiObjectProxy(this ); ????????} ????????else ?{ ????????????if ?(!this .lookupOnStartup?||?!this .cache)?{ ????????????????throw ?new ?IllegalArgumentException( ????????????????????"Cannot?deactivate?'lookupOnStartup'?or?'cache'?without?specifying?a?'proxyInterface'" ); ????????????} ????????????if ?(this .defaultObject?!=?null ?&&?getExpectedType()?!=?null ?&& ????????????????????!getExpectedType().isInstance(this .defaultObject))?{ ????????????????throw ?new ?IllegalArgumentException("Default?object?[" ?+?this .defaultObject?+ ????????????????????????"]?of?type?[" ?+?this .defaultObject.getClass().getName()?+ ????????????????????????"]?is?not?of?expected?type?[" ?+?getExpectedType().getName()?+?"]" ); ????????????} ???????????? ????????????this .jndiObject?=?lookupWithFallback(); ????????} ????}
當proxyTnterface不為空的時候 this .jndiObject?=?JndiObjectProxyFactory.createJndiObjectProxy(this ); 生成了一個從Jndi目錄中取得了的對象的代理類:
private ?static ?class ?JndiObjectProxyFactory?{????????private ?static ?Object?createJndiObjectProxy(JndiObjectFactoryBean?jof)?throws?NamingException?{ ???????????? ????????????JndiObjectTargetSource?targetSource?=?new ?JndiObjectTargetSource(); ????????????targetSource.setJndiTemplate(jof.getJndiTemplate()); ????????????targetSource.setJndiName(jof.getJndiName()); ????????????targetSource.setExpectedType(jof.getExpectedType()); ????????????targetSource.setResourceRef(jof.isResourceRef()); ????????????targetSource.setLookupOnStartup(jof.lookupOnStartup); ????????????targetSource.setCache(jof.cache); ????????????targetSource.afterPropertiesSet(); ???????????? ????????????ProxyFactory?proxyFactory?=?new ?ProxyFactory(); ????????????proxyFactory.addInterface(jof.proxyInterface); ????????????proxyFactory.setTargetSource(targetSource); ????????????return ?proxyFactory.getProxy(); ????????} ????}
否則直接將從目錄服務器中得到的對象暴露出來;如果查找出現異常,將會把DefaultObject暴露出來;
總結
以上是生活随笔 為你收集整理的从源代码解读spring之DataSource实现和FactoryBean模式(JndiObjectFactoryBean) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。