日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从源代码解读spring之DataSource实现和FactoryBean模式(JndiObjectFactoryBean)

發布時間:2024/4/17 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从源代码解读spring之DataSource实现和FactoryBean模式(JndiObjectFactoryBean) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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. ?
  • ?*/??
  • /*** 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; ??
  • /** ?
  • ?*?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(); ??
  • ????} ??
  • }??
  • 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)?{
  • ????????//?Prepend?container?prefix?if?not?already?specified?and?no?other?scheme?given.
  • ????????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'");
  • ????????????}
  • ????????????//?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();
  • ????????}
  • ????}

  • 當proxyTnterface不為空的時候
    this
    .jndiObject?=?JndiObjectProxyFactory.createJndiObjectProxy(this);
    生成了一個從Jndi目錄中取得了的對象的代理類:

  • private?static?class?JndiObjectProxyFactory?{
  • ????????private?static?Object?createJndiObjectProxy(JndiObjectFactoryBean?jof)?throws?NamingException?{
  • ????????????//?Create?a?JndiObjectTargetSource?that?mirrors?the?JndiObjectFactoryBean's?configuration.
  • ????????????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();
  • ????????????//?Create?a?proxy?with?JndiObjectFactoryBean's?proxy?interface?and?the?JndiObjectTargetSource.
  • ????????????ProxyFactory?proxyFactory?=?new?ProxyFactory();
  • ????????????proxyFactory.addInterface(jof.proxyInterface);
  • ????????????proxyFactory.setTargetSource(targetSource);
  • ????????????return?proxyFactory.getProxy();
  • ????????}
  • ????}
  • 否則直接將從目錄服務器中得到的對象暴露出來;如果查找出現異常,將會把DefaultObject暴露出來;

    總結

    以上是生活随笔為你收集整理的从源代码解读spring之DataSource实现和FactoryBean模式(JndiObjectFactoryBean)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。