码迷,mamicode.com
首页 > 编程语言 > 详细

Spring 管理数据源

时间:2016-06-30 16:08:40      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:

Spring 管理数据源

 

不管通过何种持久化技术,都必须通过数据连接访问数据库,在Spring中,数据连接是通过数据源获得的。在以往的应用中,数据源一般是Web应用服务器提供的。在Spring中,你不但可以通过JNDI获取应用服务器的数据源,也可以直接在Spring容器中配置数据源,此外,你还可以通过代码的方式创建一个数据源,以便进行无依赖的单元测试配置一个数据源。

    Spring在第三方依赖包中包含了两个数据源的实现类包,其一是ApacheDBCP,其二是 C3P0。可以在Spring配置文件中利用这两者中任何一个配置数据源。

1. Spring 配置DataSource 的三种方式

1.1. 使用Spring自带的DriverManagerDataSource

DriverManagerDataSource建立连接是只要有连接就新建一个connection,根本没有连接池的作用。 这里的引用属性是从配置文件jdbc.properties 中读取的。

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="location" value="/WEB-INF/jdbc.properties"/>      

</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName"><value>${jdbc.driverClassName}</value></property>

    <property name="url"><value>${jdbc.url}</value></property>  

    <property name="username"><value>${jdbc.username}</value></property>

    <property name="password"><value>${jdbc.password}</value></property>

</bean>

 

说明:由于其没有使用连接池,故少在项目中用到。

1.2. 使用数据源

这是一种推荐使用的数据源配置方式,它真正使用了连接池技术。Spring在第三方依赖包中包含了两个数据源的实现类包,其一是ApacheDBCP,其二是 C3P0,这里使用了DBCP

1.2.1  DBCP数据源:org.apache.commons.dbcp.BasicDataSource  

DBCP是一个依赖 Jakarta commons-pool对象池机制的数据库连接池,要在Spring中使用DBCP连接池,需要引入spring-framework-2.0-ml\lob\jakarta-commons文件夹中的commons-collections.jarcommons-dbcp.jarcommons-pool.jar。下面是DBCP配置片段:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">      

<property name="location" value="/WEB-INF/jdbc.properties"/>      

</bean>      

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">      

<property name="driverClassName" value="${jdbc.driverClassName}" />      

<property name="url" value="${jdbc.url}" />      

<property name="username" value="${jdbc.username}" />      

<property name="password" value="${jdbc.password}" />      

</bean>  

 

说明:BasicDataSource提供了close()方法关闭数据源,所以必须设定destroy-method=”close”属性, 以便Spring容器关闭时,数据源能够正常关闭。除以上必须的数据源属性外,还有一些常用的属性:

    defaultAutoCommit:设置从数据源中返回的连接是否采用自动提交机制,默认值为 true

    defaultReadOnly:设置数据源是否仅能执行只读操作, 默认值为 false

    maxActive:最大连接数据库连接数,设置为0时,表示没有限制;

    maxIdle:最大等待连接中的数量,设置为0时,表示没有限制;

    maxWait:最大等待秒数,单位为毫秒, 超过时间会报出错误信息;

    validationQuery:用于验证连接是否成功的查询SQL语句,SQL语句必须至少要返回一行数据, 如你可以简单地设置为:“select count(*) from user”;

    removeAbandoned:是否自我中断,默认是 false

    removeAbandonedTimeout:几秒后数据连接会自动断开,在removeAbandonedtrue,提供该值;

logAbandoned:是否记录中断事件, 默认为 false

 

1.2.2  C3P0数据源:com.mchange.v2.c3p0.ComboPooledDataSource

C3P0是一个开放源代码的JDBC数据源实现项目,它在lib目录中与Hibernate一起发布,实现了JDBC3JDBC2扩展规范说明的 Connection Statement 池。C3P0类包位于/lib/c3p0/c3p0-0.9.0.4.jar。下面是C3P0配置片段:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">      

<property name="driverClass" value=" oracle.jdbc.driver.OracleDriver "/>      

<property name="jdbcUrl" value=" jdbc:oracle:thin:@localhost:1521:ora9i "/>      

<property name="user" value="admin"/>      

<property name="password" value="1234"/>      

</bean>

 

 

说明:ComboPooledDataSourceBasicDataSource一样提供了一个用于关闭数据源的close()方法,这样我们就可以保证Spring容器关闭时数据源能够成功释放。

    C3P0拥有比DBCP更丰富的配置属性,通过这些属性,可以对数据源进行各种有效的控制:

    acquireIncrement:当连接池中的连接用完时,C3P0一次性创建新连接的数目;

    acquireRetryAttempts:定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30

    acquireRetryDelay:两次连接中间隔时间,单位毫秒,默认为1000

    autoCommitOnClose:连接关闭时默认将所有未提交的操作回滚。默认为false

    automaticTestTableC3P0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数,那么属性preferredTestQuery将被忽略。你 不能在这张Test表上进行任何操作,它将中为C3P0测试所用,默认为null

    breakAfterAcquireFailure:获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调   用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为 false

    checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒,默认为0

    connectionTesterClassName: 通过实现ConnectionTesterQueryConnectionTester的类来测试连接,类名需设置为全限定名。默认为 com.mchange.v2.C3P0.impl.DefaultConnectionTester

    idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;

    initialPoolSize:初始化时创建的连接数,应在minPoolSizemaxPoolSize之间取值。默认为3

    maxIdleTime:最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0

    maxPoolSize:连接池中保留的最大连接数。默认为15

    maxStatementsJDBC的标准参数,用以控制数据源内加载的PreparedStatement数量。但由于预缓存的Statement属 于单个Connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果maxStatementsmaxStatementsPerConnection均为0,则缓存被关闭。默认为0

    maxStatementsPerConnection:连接池内单个连接所拥有的最大缓存Statement数。默认为0

    numHelperThreadsC3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为3

    preferredTestQuery:定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个参数能显著提高测试速度。测试的表必须在初始数据源的时候就存在。默认为null

    propertyCycle: 用户修改系统配置参数执行前最多等待的秒数。默认为300

    testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都 将校验其有效性。建议使用idleConnectionTestPeriodautomaticTestTable

等方法来提升连接测试的性能。默认为false

    testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。默认为false

 

1.2.3  其他数据源

oracle.jdbc.pool.OracleDataSource:使用Oracle自带的数据源oracle.jdbc.pool.OracleDataSourceSpring使用完这个数据源提供的数据连接后并不进行关闭操作,需要显式的关闭连接。

org.logicalcobwebs.proxool.ProxoolDataSource: Proxool是一种Java数据库连接池技术。sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况。目前是和DBCP以及C3P0一起,最为常见的三种JDBC连接池技术。

com.jolbox.bonecp.BoneCPDataSource :bonecp数据连接池, BoneCP最大的特点就是效率,BoneCP号称是目前市面上最快的Java连接池,从官方的评测来看其效率远远超越了其它同类的Java连 接池产品

1.3. 使用Tomcat提供的JNDI

说明:JndiObjectFactoryBean 能够通过JNDI获取DataSource

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">

   <property name="jndiName">

<value>java:comp/env/jdbc/roseindiaDB_local</value>

</property>

</bean>

总结:这种方式需要在web server中配置数据源,不方便于部署。

1.4. 总结

3种方式中的第一种没有使用连接池,故少在项目中用到,第三种方式需要在web server中配置数据源,不方便于部署,推荐使用第二种方式进行数据源的配置。  

 

2. Spring持久化的设计思想

2.1. JDBC基本的编程模型

由于任何持久化层的封装实际上都是对java.sql.Connection等相关对象的操作,一个典型的数据操作的流程如下:

 

在实际使用springibatis的时候,我们都没有感觉到上面的流程,其实spring已经对外已经屏蔽了上述的操作,让我们更关注业务逻辑功能

2.2. 开启事务

在开启事务的时候,我们需要初始化事务上下文信息,以便在业务完成之后,需要知道事务的状态,以便进行后续的处理,这个上下文信息可以保存在 ThreadLocal里面,包括是否已经开启事务,事务的超时时间,隔离级别,传播级别,是否设置为回滚。这个信息对应用来说是透明的,但是提供给使用者编程接口,以便告知业务结束的时候是提交事务还是回滚事务。

 

2.3. 获取连接

首先来看看spring如何获取数据库连接的,对于正常情况来看,获取连接直接调用DataSource.getConnection()就可以了,我们在自己实现的时候也肯定会这么做,但是需要考虑两种情况(这里面先不引入事务的传播属性):

1 还没有获取过连接,这是第一次获取连接

2 已经获取过连接,不是第一次获取连接,可以复用连接

解决获取数据库连接的关键问题就是如何判断是否已经可用的连接,而不需要开启新的数据库连接,同时由于数据库连接需要给后续的业务操作复用,如何保持这个连接,并且透明的传递给后续流程。对于一个简单的实现就是使用线程上下文变量ThrealLocal来解决以上两个问题。

具体的实现是:在获取数据库连接的时候,判断当前线程线程变量里面是否已经存在相关连接,如果不存在,就创新一个新的连接,如果存在,就直接获取其对应的连接。在第一次获取到数据库连接的时候,我们还需要做一些特殊处理,就是设置自动提交为false。在业务活动结束的时候在进行提交或者回滚。这个时候就是要调用connection.setAutoCommit(false)方法。

 

2.4. 执行sql

这一部分和业务逻辑相关,通过对外提供一些编程接口,可以让业务决定业务完成之后如何处理事务,比较简单的就是设置事务状态。

 

2.5. 提交事务

在开启事务的时候,事务上下文信息已经保存在线程变量里面了,可以根据事务上下文的信息,来决定是否是提交还是回滚。其实就是调用数据库连接Connection.commit Connection.rollback 方法。然后需要清空线程变量中的事务上下文信息。相当于结束了当前的事务。  

2.6. 关闭连接

关闭连接相对比较简单,由于当前线程变量保存了连接信息,只需要获取连接之后,调用connection.close方法即可,接着清空线程变量的数据库连接信息。

 上面几个流程是一个简单的事务处理流程,在spring中都有对应的实现,见TransactionTemplate.execute方法。

2.7. 总结

当一个持久化操作结束时,数据库连接就应该关闭,而spring 封装了其他操作,我们只需要关注 “执行sql”这一步。

 

3. Spring的底层类核心代码分析

3.1. 使用JdbcTemplate

JdbcTemplate类使用DataSource得到一个数据库连接。然后,他调用StatementCreator实例创建要执行的语句。下一步,他调用StatementCallBack完成。

 一旦StatementCallBack返回结果,JdbcTemplate类完成所有必要清理工作关闭连接。如果StatementCreatorStatementCallBack抛出异常,JdbcTemplate类会捕获他们,并转换为Spring数据访问异常。

 

 

看一个JdbcTemplate里面的比较核心的一个方法:

  1. //-------------------------------------------------------------------------  
  2. // Methods dealing with prepared statements  
  3. //-------------------------------------------------------------------------  
  4. public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action)  
  5. throws DataAccessException {  
  6. Assert.notNull(psc, "PreparedStatementCreator must not be null");  
  7. Assert.notNull(action, "Callback object must not be null");  
  8. if (logger.isDebugEnabled()) {  
  9. String sql = getSql(psc);  
  10. logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));  
  11. }  
  12. Connection con = DataSourceUtils.getConnection(getDataSource());  
  13. PreparedStatement ps = null;  
  14. try {  
  15. Connection conToUse = con;  
  16. if (this.nativeJdbcExtractor != null &&  
  17. this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {  
  18. conToUse = this.nativeJdbcExtractor.getNativeConnection(con);  
  19. }  
  20. ps = psc.createPreparedStatement(conToUse);  
  21. applyStatementSettings(ps);  
  22. PreparedStatement psToUse = ps;  
  23. if (this.nativeJdbcExtractor != null) {  
  24. psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);  
  25. }  
  26. Object result = action.doInPreparedStatement(psToUse);  
  27. handleWarnings(ps);  
  28. return result;  
  29. }  
  30. catch (SQLException ex) {  
  31. // Release Connection early, to avoid potential connection pool deadlock  
  32. // in the case when the exception translator hasn‘t been initialized yet.  
  33. if (psc instanceof ParameterDisposer) {  
  34. ((ParameterDisposer) psc).cleanupParameters();  
  35. }  
  36. String sql = getSql(psc);  
  37. psc = null;  
  38. JdbcUtils.closeStatement(ps);  
  39. ps = null;  
  40. DataSourceUtils.releaseConnection(con, getDataSource());  
  41. con = null;  
  42. throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);  
  43. }  
  44. finally {  
  45. if (psc instanceof ParameterDisposer) {  
  46. ((ParameterDisposer) psc).cleanupParameters();  
  47. }  
  48. JdbcUtils.closeStatement(ps);  
  49. DataSourceUtils.releaseConnection(con, getDataSource());  
  50. }  
  51. }  

 

显然,我们在finally里面看到了关闭调用,而且从代码可以看出 JdbcTemplate是调用了DataSourceUtils的。在 Spring文档中要求尽量首先使用JdbcTemplate,其次是用DataSourceUtils来获取和释放连接

 

再看看这个关闭调用方法内部: 

  1. /** 
  2. * Close the given Connection, obtained from the given DataSource, 
  3. * if it is not managed externally (that is, not bound to the thread). 
  4. * @param con the Connection to close if necessary 
  5. * (if this is <code>null</code>, the call will be ignored) 
  6. * @param dataSource the DataSource that the Connection was obtained from 
  7. * (may be <code>null</code>) 
  8. * @see #getConnection 
  9. */  
  10. public static void releaseConnection(Connection con, DataSource dataSource) {  
  11. try {  
  12. doReleaseConnection(con, dataSource);  
  13. }  
  14. catch (SQLException ex) {  
  15. logger.debug("Could not close JDBC Connection", ex);  
  16. }  
  17. catch (Throwable ex) {  
  18. logger.debug("Unexpected exception on closing JDBC Connection", ex);  
  19. }  
  20. }  
  21. /** 
  22. * Actually close the given Connection, obtained from the given DataSource. 
  23. * Same as {@link #releaseConnection}, but throwing the original SQLException. 
  24. * <p>Directly accessed by {@link TransactionAwareDataSourceProxy}. 
  25. * @param con the Connection to close if necessary 
  26. * (if this is <code>null</code>, the call will be ignored) 
  27. * @param dataSource the DataSource that the Connection was obtained from 
  28. * (may be <code>null</code>) 
  29. * @throws SQLException if thrown by JDBC methods 
  30. * @see #doGetConnection 
  31. */  
  32. public static void doReleaseConnection(Connection con, DataSource dataSource) throws SQLException {  
  33. if (con == null) {  
  34. return;  
  35. }  
  36. if (dataSource != null) {  
  37. ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);  
  38. if (conHolder != null && connectionEquals(conHolder, con)) {  
  39. // It‘s the transactional Connection: Don‘t close it.  
  40. conHolder.released();  
  41. return;  
  42. }  
  43. }  
  44. // Leave the Connection open only if the DataSource is our  
  45. // special SmartDataSoruce and it wants the Connection left open.  
  46. if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {  
  47. logger.debug("Returning JDBC Connection to DataSource");  
  48. con.close();  
  49. }  
  50. }  


主要下面这几行代码

  1. // Leave the Connection open only if the DataSource is our  
  2. // special SmartDataSoruce and it wants the Connection left open.  
  3. if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {  
  4. logger.debug("Returning JDBC Connection to DataSource");  
  5. con.close();  
  6. }  

可以看到大部分情况下是自动关闭,除非你使用的是SmartDataSource,且SmartDataSource指定了允许关闭。

 

3.2. 使用DataSourceUtils

使用Spring DataSource进行事务管理的关键在于ConnectionHolderTransactionSynchronizationManager

  0.先从TransactionSynchronizationManager中尝试获取连接

  1.如果前一步失败则在每个线程上,对每个DataSouce只创建一个Connection

  2.这个ConnectionConnectionHolder包装起来,由TransactionSynchronizationManager管理

  3.再次请求同一个连接的时候,从TransactionSynchronizationManager返回已经创建的ConnectionHolder,然后调用ConnectionHolderrequest将引用计数+1

  4.释放连接时要调用ConnectionHolderreleased,将引用计数-1

  5.当事物完成后,将ConnectionHolderTransactionSynchronizationManager中解除。当谁都不用,这个连接被close

以上所有都是可以调用DataSourceUtils化简代码。

JdbcTemplate又是调用DataSourceUtils的。所以在Spring文档中要求尽量首先使用JdbcTemplate,其次是用DataSourceUtils来获取和释放连接。至于TransactionAwareDataSourceProxy,那是下策的下策。不过可以将Spring事务管理和遗留代码无缝集成。

 

如使用Spring的事务管理,但是又不想用JdbcTemplate,那么可以考虑TransactionAwareDataSourceProxy。这个类是原来DataSource的代理。

其次,想使用Spring事物,又不想对Spring进行依赖是不可能的。与其试图自己模拟DataSourceUtils,不如直接使用现成的

此外,如果使用DataSourceUtils类,则得到连接方法DataSourceUtils.getConnection()要与释放连接方法DataSourceUtils.releaseConnection()配合使用。

3.3. 总结

由底层代码可以看出,使用JdbcTemplate 来连接数据库不需要手动关闭连接,但是,有时还需要自己额外的拿到conn进行操作,如下: jdbcTemplate.getDataSource().getConnection() ,那么,就需要关闭连接了

而如果采用其他底层方法的话,需要使用对应的释放连接。

 

4. Spring的数据源实现类

4.1. 使用JDBC 模板来实现

Spring JDBC实现模板设计模式,这意味着,代码中的重复的复杂的任务部分是在模板类中实现的。JdbcTemplatecore包的核心类。它替我们完成了资源的创建以及释放工作,从而简化了我们对JDBC的使用。它还可以帮助我们避免一些常见的错误,比如忘记关闭数据库连接。JdbcTemplate将完成JDBC核心处理流程,比如SQL语句的创建、执行,而把SQL语句的生成以及查询结果的提取工作留给我们的应用代码。它可以完成SQL查询、更新以及调用存储过程,可以对ResultSet进行遍历并加以提取。它还可以捕获JDBC异常并将其转换成org.springframework.dao包中定义的,通用的,信息更丰富的异常。

 

SpringJdbcTemplate的工作流程如下:

(1).配置数据源:

applicationContext.xml中设置好数据源。

Spring中,将管理数据库连接的数据源当作普通Java Bean一样在Spring IoC容器中管理,当应用使用数据源时Spring IoC容器负责初始化数据源。

(2).将数据源注入JdbcTemplate

JdbcTemplatedataSource属性用于注入配置的数据源,Spring IoC容器通过依赖注入将配置的数据源注入到SpringJdbc操作的封装类JdbcTemplate中。

(3).应用中使用JdbcTemplate

注入了数据源的JdbcTemplate就可以在应用中使用了,应用中对数据源的增删改查等操作都可以使用JdbcTemplate对外提供的方法操作数据库。

实例参考:http://blog.csdn.net/chjttony/article/details/6404089

4.2. 使用DriverManagerDataSource类来实现

Spring本身也提供了一个简单的数据源实现类DriverManagerDataSource ,它位于org.springframework.jdbc.datasource包中。这个类实现了javax.sql.DataSource接口,但 它并没有提供池化连接的机制,每次调用getConnection()获取新连接时,只是简单地创建一个新的连接。因此,这个数据源类比较适合在单元测试 或简单的独立应用中使用,因为它不需要额外的依赖类。

说明:

DriverManagerDataSource :简单封装了DriverManager获取数据库连接;通过DriverManagergetConnection方法获取数据库连接;

SingleConnectionDataSource :内部封装了一个连接,该连接使用后不会关闭,且不能在多线程环境中使用,一般用于测试;

LazyConnectionDataSourceProxy :包装一个DataSource,用于延迟获取数据库连接,只有在真正创建Statement等时才获取连接,因此再说实际项目中最后使用该代理包装原始DataSource从而使得只有在真正需要连接时才去获取。

 

DataSourceUtilsSpring JDBC抽象框架内部都是通过它的getConnection(DataSource dataSource)方法获取数据库连接,releaseConnection(Connection con, DataSource dataSource) 用于释放数据库连接,DataSourceUtils用于支持Spring管理事务,只有使用DataSourceUtils获取的连接才具有Spring管理事务。

 

4.3. 使用spring getSession()

Springhibernate 集成的环境里,getSession获取的是没有经过Spring包装的原始的session,使用完之后不会自动关闭,需要调用手动调用close方法,或者releaseSession(session);getHibernateTemplate()方法是经过spring封装的,例如添加相应的声明式事务管理,由spring管理相应的连接,所以用getHibernateTemplate().find这些方法之后,spring会帮你控制数据库连接的关闭。

 

在实际的使用过程中发现的确getHibernateTemplate()getSession()方法要好很多,但是有些方法在getHibernateTemplate()并没有提供,这时我们用HibernateCallback回调的方法管理数据库.

 

例如如下代码:

return this.getHibernateTemplate().executeFind(new HibernateCallback(){  

   public List doInHibernate(Session session) throws HibernateException, SQLException {  

       Query query=session.createQuery(hqlString);  

       query.setFirstResult(startRow1);  

    query.setMaxResults(pageSize1);  

     return query.list();  

    }

});

 

但是,如果是配置了OpenSessionInView模式,则getSession拿到的sessionSpring就会负责关闭了!

 

 

5. Springbeanscope 详解

spring2.0之前bean只有2种作用域即:singleton(单例)non-singleton(也称 prototype, Spring2.0以后,增加了sessionrequestglobal session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类 型,满足实际应用需求。

<bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>   这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。

 

5.1. singleton作用域(scope 默认值)

当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把 一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中 只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时 候,springIOC容器中只会存在一个该bean

配置实例:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>

或者

<bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/>

 

5.2. prototype

prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用。)

配置实例:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/>

或者

<beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/>

 

5.3. request

 request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例:

requestsessionglobal session使用的时候首先要在初始化webweb.xml中做如下配置:

 如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可:

 

 <web-app>

    ...

   <listener>

 <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>

   </listener>

    ...

 </web-app>

 

,如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现:

<web-app>

  ..

  <filter>

     <filter-name>requestContextFilter</filter-name>

     <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>

  </filter>

  <filter-mapping>

     <filter-name>requestContextFilter</filter-name>

     <url-pattern>/*</url-pattern>

  </filter-mapping>

    ...

 </web-app>

 

接着既可以配置bean的作用域了:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>

5.4.  session

 session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例:

 配置实例:

 和request配置实例的前提一样,配置好web启动文件就可以如下配置:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>

5.5.  global session

 global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portletweb应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。

 配置实例:

 和request配置实例的前提一样,配置好web启动文件就可以如下配置:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>

5.6.  自定义bean装配作用域

 在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singletonprototype),spring的作用域由接口org.springframework.beans.factory.config.Scope来定 义,自定义自己的作用域只要实现该接口即可,下面给个实例:

 我们建立一个线程的scope,该scope在表示一个线程中有效,代码如下:

 

publicclass MyScope implements Scope {

       privatefinal ThreadLocal threadScope = new ThreadLocal() {

           protected Object initialValue() {

              returnnew HashMap();

            }

      };

      public Object get(String name, ObjectFactory objectFactory) {

          Map scope = (Map) threadScope.get();

          Object object = scope.get(name);

         if(object==null) {

            object = objectFactory.getObject();

            scope.put(name, object);

          }

         return object;

       }

      public Object remove(String name) {

          Map scope = (Map) threadScope.get();

         return scope.remove(name);

       }

       publicvoid registerDestructionCallback(String name, Runnable callback) {

       }

     public String getConversationId() {

        // TODO Auto-generated method stub

         returnnull;

      }

 }

6. 使用Spring操作数据库需要显式关闭数据库连接的情况

1、 配置数据源时,需要添加 destroy-method 属性,DBCPC3PO 都提供了close()方法关闭数据源,所以必须设定destroy-method=”close” 属性, 以便Spring容器关闭时,数据源能够正常关闭

2、 如果使用spring bean 的作用域为 prototype ,需要在应用程序中 手动关闭数据库

3、 使用JdbcTemplate 来连接数据库不需要手动关闭连接,但是,有时还需要自己额外的拿到conn进行操作,如下: jdbcTemplate.getDataSource().getConnection() 那么,就需要关闭连接了

4、 直接使用DataSourceUtils.getConnection()方法得到连接,则需要使用DataSourceUtils.releaseConnection()方法 来释放连接了

5、 若是使用的是比DataSourceUtils 更底层的代码,则必须要显式关闭连接了

Spring 管理数据源

标签:

原文地址:http://www.cnblogs.com/panie2015/p/5630142.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!