<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    午后星期午

    Spring的JNDI數據源連接池配置示例及Spring對JNDI實現分析

    個人學習參考所用,勿噴!

     

    在使用 Tomcat服務器 + SpringFramework 進行JavaEE項目的開發部署的時候可以在Tomcat的配置文件中進行JDBC數據源的配置,具體步驟如下(這里省略了工程的建立步驟):

     

    1) 添加如下代碼到tomcat的conf目錄下的server.xml中:

    Xml代碼  收藏代碼
    1. <Context>   
    2.     <Resource name="jdbc/demoDB" auth="Container"   
    3.     type="javax.sql.DataSource"  
    4.     driverClassName="com.mysql.jdbc.Driver"  
    5.     url="jdbc:mysql://localhost:3306/demo"  
    6.     username="root"  
    7.     password="123"  
    8.     maxActive="50"  
    9.     maxIdle="30"  
    10.     maxWait="10000" />  
    11. </Context>  

     完成上述步驟數據源的連接池配置已經完成,但是為了提高項目的可移植性,最好將上述第二步的內容放入到工程的META-INF目錄的context.xml中(這個文件需要自行建立):

    Xml代碼  收藏代碼
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <Context>  
    3.       <Resource name="jdbc/demoDB" auth="Container"   
    4.       type="javax.sql.DataSource"  
    5.       driverClassName="com.mysql.jdbc.Driver"  
    6.       url="jdbc:mysql://localhost:3306/demo"  
    7.       username="root"  
    8.       password="123"  
    9.       maxActive="50"  
    10.       maxIdle="30"  
    11.       maxWait="10000" />  
    12. </Context>  

     

    2)在Spring的配置文件,如applicationContext.xml中配置配置如下內容:

    Xml代碼  收藏代碼
    1. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">  
    2. <beans>  
    3.     <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">  
    4.         <property name="jndiName">  
    5.             <value>java:comp/env/jdbc/demoDB</value>  
    6.         </property>  
    7.     </bean>  
    8.     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
    9.         <property name="dataSource">  
    10.             <ref bean="dataSource" />  
    11.         </property>  
    12.     </bean>  
    13.       
    14.     <!-- 這里是自定義的數據庫基礎操作類 -->  
    15.     <bean id="sqlBaseDAO" class="demo.BaseDAOImpl">  
    16.         <property name="jdbcTemplate">  
    17.             <ref bean="jdbcTemplate" />  
    18.         </property>  
    19.     </bean>  
    20. </beans>  

     

    3)建立數據庫基礎操作類 BaseDAOImpl

        接口代碼:

    Java代碼  收藏代碼
    1. public interface BaseDAO {  
    2.   
    3.     public List<Map<String, Object>> select(String sql);  
    4.   
    5.     public void update(String how);  
    6.   
    7.     public void insert(Object obj);  
    8.   
    9.     public void insert(String sql);  
    10.   
    11.     public void save(String sql);  
    12.   
    13.     public void edit(String sql);  
    14.   
    15.     public void execute(String sql, PreparedStatementCallback callback);  
    16.       
    17.     public void delete(String sql);  
    18.   
    19.     public void insertObjects(String[] sqls);  
    20.   
    21.     public Connection getConnection() throws Exception;  
    22.   
    23. }  

     

       實現類代碼:

    Java代碼  收藏代碼
    1. public class BaseDAOImpl implements BaseDAO {  
    2.     private JdbcTemplate jdbcTemplate;  
    3.   
    4.     public void setJdbcTemplate(JdbcTemplate jdbcTemplate){  
    5.         this.jdbcTemplate = jdbcTemplate;  
    6.     }  
    7.   
    8.     public void insert(Object obj) {  
    9.   
    10.     }  
    11.   
    12.     public void insert(String sql) {  
    13.         jdbcTemplate.execute(sql);  
    14.     }  
    15.   
    16.     public void insertObjects(String[] sqls) {  
    17.         jdbcTemplate.batchUpdate(sqls);  
    18.     }  
    19.   
    20.     public List<Map<String, Object>> select(String sql) {  
    21.         return jdbcTemplate.queryForList(sql);  
    22.     }  
    23.   
    24.     public void update(String how) {  
    25.         jdbcTemplate.update(how);  
    26.   
    27.     }  
    28.   
    29.     public void delete(String sql) {  
    30.         if (sql == null) {  
    31.             return;  
    32.         }  
    33.         jdbcTemplate.execute(sql);  
    34.     }  
    35.   
    36.     public void edit(String sql) {  
    37.         if (sql == null) {  
    38.             return;  
    39.         }  
    40.         jdbcTemplate.execute(sql);  
    41.     }  
    42.   
    43.     public void execute(String sql, PreparedStatementCallback callback) {  
    44.         jdbcTemplate.execute(sql, callback);  
    45.     }  
    46.       
    47.     public void save(String sql) {  
    48.         if (sql == null) {  
    49.             return;  
    50.         }  
    51.         jdbcTemplate.execute(sql);  
    52.     }  
    53.   
    54.     public Connection getConnection() throws Exception {  
    55.         Connection conn = jdbcTemplate.getDataSource().getConnection();  
    56.         return conn;  
    57.     }  
    58.   
    59. }  

     

     

    這里存在一個疑問:

    運行如下代碼:

    Java代碼  收藏代碼
    1. public static void main(String[] args) {  
    2.     org.springframework.jndi.JndiObjectFactoryBean jofb = new org.springframework.jndi.JndiObjectFactoryBean();  
    3.     javax.sql.DataSource ds = (javax.sql.DataSource)jofb;  
    4.     org.springframework.jdbc.core.JdbcTemplate jTemplate = new org.springframework.jdbc.core.JdbcTemplate();  
    5.     jTemplate.setDataSource(ds);  
    6. }  

     

    會報告如下的錯誤:

    Out代碼  收藏代碼
    1. Exception in thread "main" java.lang.ClassCastException: org.springframework.jndi.JndiObjectFactoryBean cannot be cast to javax.sql.DataSource  

    從JndiObjectFactoryBean的源碼中也可以看到,JndiObjectFactoryBean的父類或所繼承的接口都沒有繼承javax.sql.DataSource接口,所以一下的配置中:

    Xml代碼  收藏代碼
    1. <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">  
    2.     <property name="jndiName">  
    3.         <value>java:comp/env/jdbc/portalDataService</value>  
    4.     </property>  
    5. </bean>  
    6. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  
    7.     <property name="dataSource">  
    8.         <ref bean="dataSource" />  
    9.     </property>  
    10. </bean>  

     對org.springframework.jdbc.core.JdbcTemplate的dataSource屬性的注入為何能夠成功?

     

    帶著這樣的疑問去iteye中提問,沒有得到詳細的解答,但是iteye的提示功能似乎很不錯,在問題的下方給出了相關內容參考提示,進入到《從源代碼解讀spring之DataSource實現和FactoryBean模式》這個帖子中,看完以后大受啟發。一下是從這篇帖子摘抄出來的內容:

     

     

    再看源碼后發現,JndiObjectFactoryBean實現了FactoryBean接口,下面是org.springframework.beans.factory.FactoryBean源代碼里一段注釋: 

     

    Java代碼  收藏代碼
    1. /**  
    2.  * Interface to be implemented by objects used within a BeanFactory  
    3.  * that are themselves factories. If a bean implements this interface,  
    4.  * it is used as a factory, not directly as a bean.  
    5.  *  
    6.  * <p><b>NB: A bean that implements this interface cannot be used  
    7.  * as a normal bean.</b> A FactoryBean is defined in a bean style,  
    8.  * but the object exposed for bean references is always the object  
    9.  * that it creates.  
    10.  */   

     

    翻譯過來是說:所有實現FactoryBean接口的類都被當作工廠來使用,而不是簡單的直接當作bean來使用,FactoryBean實現類里定義了要生產的對象,并且由FactoryBean實現類來造該對象的實例,看到這里聰明的大概已經能猜出個八九不離十了吧,我們回過頭來看看 JndiObjectFactoryBean的實現細節 :

     

    Java代碼  收藏代碼
    1. private Object jndiObject;    
    2. /**  
    3.  * Look up the JNDI object and store it.  
    4.  * 廣義上說是造對象的過程,就本例而言,是通過JNDI獲得DataSource對象  
    5.  */    
    6. public void afterPropertiesSet() throws IllegalArgumentException, NamingException {    
    7.     super.afterPropertiesSet();    
    8.     
    9.     if (this.proxyInterface != null) {    
    10.         if (this.defaultObject != null) {    
    11.             throw new IllegalArgumentException(    
    12.                     "'defaultObject' is not supported in combination with 'proxyInterface'");    
    13.         }    
    14.         // We need a proxy and a JndiObjectTargetSource.    
    15.         this.jndiObject = JndiObjectProxyFactory.createJndiObjectProxy(this);    
    16.     }    
    17.     
    18.     else {    
    19.         if (!this.lookupOnStartup || !this.cache) {    
    20.             throw new IllegalArgumentException(    
    21.                 "Cannot deactivate 'lookupOnStartup' or 'cache' without specifying a 'proxyInterface'");    
    22.         }    
    23.         if (this.defaultObject != null && getExpectedType() != null &&    
    24.                 !getExpectedType().isInstance(this.defaultObject)) {    
    25.             throw new IllegalArgumentException("Default object [" + this.defaultObject +    
    26.                     "] of type [" + this.defaultObject.getClass().getName() +    
    27.                     "] is not of expected type [" + getExpectedType().getName() + "]");    
    28.         }    
    29.         // Locate specified JNDI object.    
    30.         this.jndiObject = lookupWithFallback();    
    31.     }    
    32. }    
    33. /**  
    34.  * Return the singleton JNDI object.  
    35.  * 返回JNDI對象(DataSource對象)  
    36.  */    
    37. public Object getObject() {    
    38.     return this.jndiObject;    
    39. }    
    40.     
    41. public Class getObjectType() {    
    42.     if (this.proxyInterface != null) {    
    43.         return this.proxyInterface;    
    44.     }    
    45.     else if (this.jndiObject != null) {    
    46.         return this.jndiObject.getClass();    
    47.     }    
    48.     else {    
    49.         return getExpectedType();    
    50.     }    
    51. }    

     

    對于JndiObjectFactoryBean對象,spring IOC容器啟動時確實造了它的對象,只不過這時是工廠本身,spring會自動調用工廠里的afterPropertiesSet()方法去造真正需要的 bean,然后調用getObject()和getObjectType()方法返回已造好的對象和類型,再將其準確的注入依賴它的其他bean里面。


     

    好吧,也許上面org.springframework.beans.factory.FactoryBean的注釋看起來像家長教育孩子該怎么怎么,那么Spring到底是怎么實現這種思想的呢?參考《Spring技術內幕》中2.5.3節對FactoryBean的實現的講解,結合Spring 的源碼可以看到:

         常見的工廠Bean是怎樣實現的,這些FactoryBean為應用生成需要的對象,這些對象往往是經過特殊處理的,比如像 ProxyFactoryBean 這樣的特殊 Bean。FactoryBean 的生產特性是在getBean中起作用的,我們看到下面的調用:

    再來看FactoryBean特性的實現:

     

    Java代碼  收藏代碼
    1. //該方法在org.springframework.beans.factory.support.AbstractBeanFactory類中  
    2. protected Object getObjectForBeanInstance(  
    3.         Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {  
    4.   
    5.     // Don't let calling code try to dereference the factory if the bean isn't a factory.  
    6.     // 如果這里不是對FactoryBean的調用,那么結束處理。  
    7.     if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {  
    8.         throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());  
    9.     }  
    10.   
    11.     // Now we have the bean instance, which may be a normal bean or a FactoryBean.  
    12.     // If it's a FactoryBean, we use it to create a bean instance, unless the  
    13.     // caller actually wants a reference to the factory.  
    14.     if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {  
    15.         return beanInstance;  
    16.     }  
    17.   
    18.     Object object = null;  
    19.     if (mbd == null) {  
    20.         object = getCachedObjectForFactoryBean(beanName);  
    21.     }  
    22.     if (object == null) {  
    23.         // Return bean instance from factory.  
    24.         FactoryBean<?> factory = (FactoryBean<?>) beanInstance;  
    25.         // Caches object obtained from FactoryBean if it is a singleton.  
    26.         if (mbd == null && containsBeanDefinition(beanName)) {  
    27.             mbd = getMergedLocalBeanDefinition(beanName);  
    28.         }  
    29.         boolean synthetic = (mbd != null && mbd.isSynthetic());  
    30.         //這里從FactoryBean中得到bean。   
    31.         object = getObjectFromFactoryBean(factory, beanName, !synthetic);  
    32.     }  
    33.     return object;  
    34. }  
    35.   
    36. //該方法在org.springframework.beans.factory.support.FactoryBeanRegistrySupport類中  
    37. protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {  
    38.     if (factory.isSingleton() && containsSingleton(beanName)) {  
    39.         synchronized (getSingletonMutex()) {  
    40.             Object object = this.factoryBeanObjectCache.get(beanName);  
    41.             if (object == null) {  
    42.                 object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);  
    43.                 this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));  
    44.             }  
    45.             return (object != NULL_OBJECT ? object : null);  
    46.         }  
    47.     }  
    48.     else {  
    49.         return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);  
    50.     }  
    51. }  
    52.   
    53. //該方法在org.springframework.beans.factory.support.FactoryBeanRegistrySupport類中  
    54. private Object doGetObjectFromFactoryBean(  
    55.         final FactoryBean factory, final String beanName, final boolean shouldPostProcess)  
    56.         throws BeanCreationException {  
    57.   
    58.     Object object;  
    59.     //這里調用factory的getObject方法來從FactoryBean中得到bean。  
    60.     try {  
    61.         if (System.getSecurityManager() != null) {  
    62.             AccessControlContext acc = getAccessControlContext();  
    63.             try {  
    64.                 object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {  
    65.                     public Object run() throws Exception {  
    66.                             return factory.getObject();  
    67.                         }  
    68.                     }, acc);  
    69.             }  
    70.             catch (PrivilegedActionException pae) {  
    71.                 throw pae.getException();  
    72.             }  
    73.         }  
    74.         else {  
    75.             object = factory.getObject();  
    76.         }  
    77.     }  
    78.     catch (FactoryBeanNotInitializedException ex) {  
    79.         throw new BeanCurrentlyInCreationException(beanName, ex.toString());  
    80.     }  
    81.     catch (Throwable ex) {  
    82.         throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);  
    83.     }  
    84.       
    85.     // Do not accept a null value for a FactoryBean that's not fully  
    86.     // initialized yet: Many FactoryBeans just return null then.  
    87.     if (object == null && isSingletonCurrentlyInCreation(beanName)) {  
    88.         throw new BeanCurrentlyInCreationException(  
    89.                 beanName, "FactoryBean which is currently in creation returned null from getObject");  
    90.     }  
    91.   
    92.     if (object != null && shouldPostProcess) {  
    93.         try {  
    94.             object = postProcessObjectFromFactoryBean(object, beanName);  
    95.         }  
    96.         catch (Throwable ex) {  
    97.             throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);  
    98.         }  
    99.     }  
    100.   
    101.     return object;  
    102. }  

         這里返回的已經是作為工廠的 FactoryBean 生產的產品,并不是 FactoryBean 本身。這種FactoryBean的機制可以為我們提供一個很好的封裝機制,比如封裝Proxy、RMI、JNDI等。經過對FactoryBean實現過程的原理分析,相信讀者會對getObject方法有很深刻的印象。這個方法就是主要的FactoryBean 的接口,需要實現特定的工廠的生產過程,至于這個生產過程是怎樣和IoC容器整合的,就是我們在上面分析的內容。

     

    那么返回的類型是怎么確定為javax.sql.DataSource類型的呢?回頭再看在context.xml中的數據源配置可以看到:

     

    Xml代碼  收藏代碼
    1. type="javax.sql.DataSource"  

    這樣一句。然后在去細看JndiObjectFactoryBean類中的afterPropertiesSet方法的具體代碼所以一切都明了了。

     

    綜上所述,這里主要還是要對Spring的FactoryBean模式的理解最為重要。

    posted on 2013-12-31 14:28 午后星期午 閱讀(361) 評論(0)  編輯  收藏 所屬分類: JavaEE

    主站蜘蛛池模板: 亚洲av之男人的天堂网站| 亚洲人成影院在线观看| 免费一级毛片在播放视频| 亚洲人成人无码网www国产| 亚洲人精品午夜射精日韩 | 国产色爽免费无码视频| 久久午夜羞羞影院免费观看| 无码少妇一区二区浪潮免费| 免费一级一片一毛片| 亚洲高清国产拍精品26U| 亚洲AV无码一区二区三区在线| 亚洲a无码综合a国产av中文| 好吊色永久免费视频大全| 3d动漫精品啪啪一区二区免费 | 国产免费一级高清淫曰本片| 84pao国产成视频免费播放| 女人18毛片水真多免费看| 中文亚洲AV片在线观看不卡 | 一级毛片aaaaaa免费看| 国产一级淫片视频免费看| 亚洲高清资源在线观看| 国产免费人成视频尤勿视频| 日韩在线免费看网站| 亚洲精品免费视频| h片在线播放免费高清| 妞干网免费视频观看| 日韩精品一区二区亚洲AV观看 | 欧美在线看片A免费观看| 亚洲av无码乱码国产精品| 人成免费在线视频| 在线观看成人免费| 亚洲美女在线观看播放| 热99RE久久精品这里都是精品免费| 国产精品久久久久影院免费| 亚洲综合校园春色| 久久免费国产视频| 亚洲线精品一区二区三区| 看免费毛片天天看| 精品国产免费一区二区| 亚洲最大成人网色香蕉| www.免费在线观看|