Spring 容器被包含在web容器里面的

所以,要让你的Spring应用使用配置在web容器里面的jndi资源,比如数据库连接,必须采用以下步骤,我们这里以tomcat作为web容器的例子

 

(1) 在你的应用里面使用资源

比如以下代码中,注入了 catalogSessionFactory 资源

 

  1. /** 
  2.  * 
  3.  * Description: 
  4.  * 
  5.  * @author charles.wang 
  6.  * @created Mar 19, 2012 1:30:38 PM 
  7.  *  
  8.  */ 
  9. @Repository("homepageHotCategoryDao"
  10. public class HotCategoryDaoImpl implements IHotCategoryDao { 
  11.  
  12.     private  Logger logger=LoggerFactory.getLogger(HotProductDaoImpl.class); 
  13.      
  14.     @Resource(name = "catalogSessionFactory"
  15.     SessionFactory sessionFactory; 
  16.      
  17.     /* (non-Javadoc) 
  18.      * @see com.bleum.canton.homepage.dao.IHotCategoryDao#addHotCategory(com.bleum.canton.homepage.entity.HotCategory) 
  19.      */ 
  20.     @Transactional 
  21.     public void addHotCategory(HotCategory pHotCategory) throws HibernateException { 
  22.         // TODO Auto-generated method stub 
  23.         Session session = sessionFactory.getCurrentSession();       
  24.         session.save(pHotCategory); 
  25.         session.flush(); 
  26.     } 
  27.  
  28.     /* (non-Javadoc) 
  29.      * @see com.bleum.canton.homepage.dao.IHotCategoryDao#findTop6HotCategoryIds() 
  30.      */ 
  31.     @Transactional 
  32.     public List<String> findTopHotCategoryIds(int number) { 
  33.         if(number<=0){ 
  34.             if(logger.isDebugEnabled()){ 
  35.                 logger.debug("the number must be non-negative"); 
  36.             } 
  37.             return null
  38.         } 
  39.              
  40.         // TODO Auto-generated method stub 
  41.         Session session = sessionFactory.getCurrentSession(); 
  42.         String findHotCategories ="FROM HotCategory";        
  43.         Query query=session.createQuery(findHotCategories);        
  44.         if( (query.list()==null ) || (query.list().size()==0) ) 
  45.             return null
  46.          
  47.         List<HotCategory> hotCategories =  query.list(); 
  48.         if(hotCategories.size()<number){ 
  49.             if(logger.isDebugEnabled()){ 
  50.                 logger.debug("we don't have enough hot categories to display ,it must be at least 3"); 
  51.             } 
  52.             return null
  53.         } 
  54.          
  55.         List<String> topHotCategoryIds = new ArrayList<String> (); 
  56.         for(int i=0;i<number;i++){ 
  57.             //top3HotProductIds.add(hotProducts.get(i).getProductId()); 
  58.             topHotCategoryIds.add(hotCategories.get(i).getCategoryId()); 
  59.         } 
  60.          
  61.         return topHotCategoryIds; 
  62.     } 
  63.  
  64.     /* (non-Javadoc) 
  65.      * @see com.bleum.canton.homepage.dao.IHotCategoryDao#updateHotCategory(com.bleum.canton.homepage.entity.HotCategory) 
  66.      */ 
  67.     @Transactional 
  68.     public void updateHotCategory(HotCategory pHotCategory) { 
  69.         // TODO Auto-generated method stub 
  70.         Session session = sessionFactory.getCurrentSession(); 
  71.         session.update(pHotCategory); 
  72.         session.flush(); 
  73.     } 
  74.  
  75.     /* (non-Javadoc) 
  76.      * @see com.bleum.canton.homepage.dao.IHotCategoryDao#findHotCategoryById(int) 
  77.      */ 
  78.     @Transactional 
  79.     public HotCategory findHotCategoryById(int pHotCategoryId) { 
  80.         // TODO Auto-generated method stub 
  81.         Session session = sessionFactory.getCurrentSession(); 
  82.         String findByIDHQL = "from HotCategory as p WHERE p.id=:id"
  83.         Query query =session.createQuery(findByIDHQL); 
  84.         query.setInteger("id", pHotCategoryId); 
  85.          
  86.         if( (query.list()==null ) || (query.list().size()==0) ) 
  87.         return null
  88.          
  89.         return (HotCategory)query.list().get(0); 
  90.     } 
  91.  
  92.     /* (non-Javadoc) 
  93.      * @see com.bleum.canton.homepage.dao.IHotCategoryDao#deleteHotCategoryById(int) 
  94.      */ 
  95.     @Transactional 
  96.     public void deleteHotCategoryById(int pHotCategoryId) throws HibernateException { 
  97.         // TODO Auto-generated method stub 
  98.         Session session = sessionFactory.getCurrentSession(); 
  99.         HotCategory deleteHotCategory = this.findHotCategoryById(pHotCategoryId); 
  100.         session.delete(deleteHotCategory); 
  101.         session.flush(); 
  102.     } 
  103.  

 

而这个资源需要在Spring配置文件中声明,不难发现,他其实引用了catalogDataSource数据源资源

  1. <bean id="catalogSessionFactory" parent="xsessionFactory"> 
  2.         <property name="dataSource" ref="catalogDataSource" /> 
  3.         <property name="packagesToScan"> 
  4.             <list> 
  5.                 <value>com.bleum.canton.itempage.entity</value> 
  6.                 <value>com.bleum.canton.homepage.entity</value> 
  7.             </list> 
  8.         </property> 
  9.     </bean> 

这个catalogDataSource肯定最终是配置在web容器里面的,所以我们先假想定义一个Spring的jndi,并且在 web.xml里面配置好hook ,注意,这里的jndi并不是真实的web容器的jndi,而是Spring 容器的jndi,它从WEB-INF/web.xml中获得引用

  1. <!-- Load Data Sources by JNDI --> 
  2.     <jee:jndi-lookup id="estoreDataSource" jndi-name="jdbc/Canton_Estore_DB" /> 
  3.     <jee:jndi-lookup id="caDataSource" jndi-name="jdbc/Canton_CA_DB" /> 
  4.     <jee:jndi-lookup id="catalogDataSource" jndi-name="jdbc/Canton_Catalog_DB" /> 
  5.     <jee:jndi-lookup id="omsDataSource" jndi-name="jdbc/Canton_OMS_DB" /> 
  6.     <jee:jndi-lookup id="paymentDataSource" jndi-name="jdbc/Canton_Payment_DB" /> 

web.xml中会声明这些jndi引用的"钩子”

 

  1. <!-- JNDI Resource Refer --> 
  2.     <resource-ref> 
  3.         <description>Canton Estore Data Source</description> 
  4.         <res-ref-name>jdbc/Canton_Estore_DB</res-ref-name> 
  5.         <res-type>javax.sql.XADataSource</res-type> 
  6.         <res-auth>Container</res-auth> 
  7.     </resource-ref> 
  8.  
  9.     <resource-ref> 
  10.         <description>Canton CA Data Source</description> 
  11.         <res-ref-name>jdbc/Canton_CA_DB</res-ref-name> 
  12.         <res-type>javax.sql.XADataSource</res-type> 
  13.         <res-auth>Container</res-auth> 
  14.     </resource-ref> 
  15.  
  16.     <resource-ref> 
  17.         <description>Canton Catalog Data Source</description> 
  18.         <res-ref-name>jdbc/Canton_Catalog_DB</res-ref-name> 
  19.         <res-type>javax.sql.XADataSource</res-type> 
  20.         <res-auth>Container</res-auth> 
  21.     </resource-ref> 
  22.  
  23.     <resource-ref> 
  24.         <description>Canton OMS Data Source</description> 
  25.         <res-ref-name>jdbc/Canton_OMS_DB</res-ref-name> 
  26.         <res-type>javax.sql.XADataSource</res-type> 
  27.         <res-auth>Container</res-auth> 
  28.     </resource-ref> 
  29.  
  30.     <resource-ref> 
  31.         <description>Canton Payment Data Source</description> 
  32.         <res-ref-name>jdbc/Canton_Payment_DB</res-ref-name> 
  33.         <res-type>javax.sql.XADataSource</res-type> 
  34.         <res-auth>Container</res-auth> 
  35.     </resource-ref> 

而这些与此同时,web容器上,也已经配置好了真实的jndi资源,见$CATALINA_HOME/conf/server.xml

 

  1. <GlobalNamingResources> 
  2.  
  3.         <!-- Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/--> 
  4.  
  5.         <!-- Data Sources Configuration for Canton --> 
  6.  
  7.         <!-- estore --> 
  8.  
  9.         <Resource auth="Container" driverClassName="oracle.jdbc.xa.client.OracleXADataSource" factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" maxActive="5" maxIdle="5" maxWait="-1" name="jdbc/Canton_Estore_DB" password="Canton_Estore_QA" type="javax.sql.DataSource" url="jdbc:oracle:thin:@192.168.129.14:15210:ora11g" username="Canton_Estore_QA"/> 
  10.  
  11.  
  12.  
  13.         <Resource auth="Container" driverClassName="oracle.jdbc.xa.client.OracleXADataSource" factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" maxActive="5" maxIdle="5" maxWait="-1" name="jdbc/Canton_CA_DB" password="Canton_CA_QA" type="javax.sql.DataSource" url="jdbc:oracle:thin:@192.168.129.14:15210:ora11g" username="Canton_CA_QA"/> 
  14.  
  15.          
  16.  
  17.         <Resource auth="Container" driverClassName="oracle.jdbc.xa.client.OracleXADataSource" factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" maxActive="5" maxIdle="5" maxWait="-1" name="jdbc/Canton_Catalog_DB" password="Canton_Catalog_QA" type="javax.sql.DataSource" url="jdbc:oracle:thin:@192.168.129.14:15210:ora11g" username="Canton_Catalog_QA"/> 
  18.  
  19.          
  20.  
  21.         <Resource auth="Container" driverClassName="oracle.jdbc.xa.client.OracleXADataSource" factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" maxActive="5" maxIdle="5" maxWait="-1" name="jdbc/Canton_OMS_DB" password="Canton_OMS_QA" type="javax.sql.DataSource" url="jdbc:oracle:thin:@192.168.129.14:15210:ora11g" username="Canton_OMS_QA"/> 
  22.  
  23.          
  24.  
  25.         <Resource auth="Container" driverClassName="oracle.jdbc.xa.client.OracleXADataSource" factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" maxActive="5" maxIdle="5" maxWait="-1" name="jdbc/Canton_Payment_DB" password="Canton_Payment_QA" type="javax.sql.DataSource" url="jdbc:oracle:thin:@192.168.129.14:15210:ora11g" username="Canton_Payment_QA"/> 
  26.  
  27.          
  28.  
  29.     </GlobalNamingResources> 

那么谁来充当web.xml里面的钩子以及web容器上真实的资源之间的粘合剂呢,在tomcat中,我们用的就是META-INF/context.xml,这个文件,才吧项目中的jndi的需求和真正容器上实际提供的jndi资源结合了起来

 

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <Context> 
  3.     <ResourceLink global="jdbc/Canton_Estore_DB" name="jdbc/Canton_Estore_DB" type="javax.sql.DataSource" /> 
  4.     <ResourceLink global="jdbc/Canton_CA_DB" name="jdbc/Canton_CA_DB" type="javax.sql.DataSource" /> 
  5.     <ResourceLink global="jdbc/Canton_Catalog_DB" name="jdbc/Canton_Catalog_DB" type="javax.sql.DataSource" /> 
  6.     <ResourceLink global="jdbc/Canton_OMS_DB" name="jdbc/Canton_OMS_DB" type="javax.sql.DataSource" /> 
  7.     <ResourceLink global="jdbc/Canton_Payment_DB" name="jdbc/Canton_Payment_DB" type="javax.sql.DataSource" /> 
  8. </Context>