OSGI环境中Quartz2.2.0使用数据库连接池

  有任务调度需求的人对Quartz应该不会陌生,目前,Quartz的最新版本是2.2.0,该文章也是基于2.2.0版本。为了保证任务调度系统的HA,对于JobStore我采用了数据库存储的方式。系统出现故障时,系统中正在执行的任务会在数据库中保存,并在系统恢复正常后,Quartz根据misfire的处理策略对任务进行重新调度。

  Quartz2.2.0默认使用的数据库连接池为c3p0。在OSGI环境中,使用该连接池时,会出现连不上数据库的错误。为了解决该问题:主要有两种思路,(1)查看C3P0的源码,修改其中不适合OSGI环境的地方。(2)对Quartz2.2.0提供其它数据库连接池的支持,比如dbcp。对于第一种方法,C3P0的源码繁多,对于工期紧的项目,工作量大,可行度压力大。对于第二种方法,通过了解Quartz2.2.0的源码,发现可行性较高。

  在Quartz中,首先我们看看Quartz是如何使用连接池以及如何设置默认的数据库连接池的。

  在StdSchedulerFactory类的instantiate()方法中,有如下一段:

  1 // Set up any DataSources
  2         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3 
  4         String[] dsNames = cfg.getPropertyGroups(PROP_DATASOURCE_PREFIX);
  5         for (int i = 0; i < dsNames.length; i++) {
  6             PropertiesParser pp = new PropertiesParser(cfg.getPropertyGroup(
  7                     PROP_DATASOURCE_PREFIX + "." + dsNames[i], true));
  8 
  9             String cpClass = pp.getStringProperty(PROP_CONNECTION_PROVIDER_CLASS, null);
 10 
 11             // custom connectionProvider...
 12             if(cpClass != null) {
 13                 ConnectionProvider cp = null;
 14                 try {
 15                     cp = (ConnectionProvider) loadHelper.loadClass(cpClass).newInstance();
 16                 } catch (Exception e) {
 17                     initException = new SchedulerException("ConnectionProvider class '" + cpClass
 18                             + "' could not be instantiated.", e);
 19                     throw initException;
 20                 }
 21 
 22                 try {
 23                     // remove the class name, so it isn't attempted to be set
 24                     pp.getUnderlyingProperties().remove(
 25                             PROP_CONNECTION_PROVIDER_CLASS);
 26 
 27                     setBeanProps(cp, pp.getUnderlyingProperties());
 28                     cp.initialize();
 29                 } catch (Exception e) {
 30                     initException = new SchedulerException("ConnectionProvider class '" + cpClass
 31                             + "' props could not be configured.", e);
 32                     throw initException;
 33                 }
 34 
 35                 dbMgr = DBConnectionManager.getInstance();
 36                 dbMgr.addConnectionProvider(dsNames[i], cp);
 37             } else {
 38                 String dsJndi = pp.getStringProperty(PROP_DATASOURCE_JNDI_URL, null);
 39 
 40                 if (dsJndi != null) {
 41                     boolean dsAlwaysLookup = pp.getBooleanProperty(
 42                             PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP);
 43                     String dsJndiInitial = pp.getStringProperty(
 44                             PROP_DATASOURCE_JNDI_INITIAL);
 45                     String dsJndiProvider = pp.getStringProperty(
 46                             PROP_DATASOURCE_JNDI_PROVDER);
 47                     String dsJndiPrincipal = pp.getStringProperty(
 48                             PROP_DATASOURCE_JNDI_PRINCIPAL);
 49                     String dsJndiCredentials = pp.getStringProperty(
 50                             PROP_DATASOURCE_JNDI_CREDENTIALS);
 51                     Properties props = null;
 52                     if (null != dsJndiInitial || null != dsJndiProvider
 53                             || null != dsJndiPrincipal || null != dsJndiCredentials) {
 54                         props = new Properties();
 55                         if (dsJndiInitial != null) {
 56                             props.put(PROP_DATASOURCE_JNDI_INITIAL,
 57                                     dsJndiInitial);
 58                         }
 59                         if (dsJndiProvider != null) {
 60                             props.put(PROP_DATASOURCE_JNDI_PROVDER,
 61                                     dsJndiProvider);
 62                         }
 63                         if (dsJndiPrincipal != null) {
 64                             props.put(PROP_DATASOURCE_JNDI_PRINCIPAL,
 65                                     dsJndiPrincipal);
 66                         }
 67                         if (dsJndiCredentials != null) {
 68                             props.put(PROP_DATASOURCE_JNDI_CREDENTIALS,
 69                                     dsJndiCredentials);
 70                         }
 71                     }
 72                     JNDIConnectionProvider cp = new JNDIConnectionProvider(dsJndi,
 73                             props, dsAlwaysLookup);
 74                     dbMgr = DBConnectionManager.getInstance();
 75                     dbMgr.addConnectionProvider(dsNames[i], cp);
 76                 } else {
 77                     String dsDriver = pp.getStringProperty(PoolingConnectionProvider.DB_DRIVER);
 78                     String dsURL = pp.getStringProperty(PoolingConnectionProvider.DB_URL);
 79 
 80                     if (dsDriver == null) {
 81                         initException = new SchedulerException(
 82                                 "Driver not specified for DataSource: "
 83                                         + dsNames[i]);
 84                         throw initException;
 85                     }
 86                     if (dsURL == null) {
 87                         initException = new SchedulerException(
 88                                 "DB URL not specified for DataSource: "
 89                                         + dsNames[i]);
 90                         throw initException;
 91                     }
 92                     try {
 93                         PoolingConnectionProvider cp = new PoolingConnectionProvider(pp.getUnderlyingProperties());
 94                         dbMgr = DBConnectionManager.getInstance();
 95                         dbMgr.addConnectionProvider(dsNames[i], cp);
 96                     } catch (SQLException sqle) {
 97                         initException = new SchedulerException(
 98                                 "Could not initialize DataSource: " + dsNames[i],
 99                                 sqle);
100                         throw initException;
101                     }
102                 }
103 
104             }
105 
106         }

 从上面这段源码可以看出,如果在quartz.properties配置文件中没有设置PROP_CONNECTION_PROVIDER_CLASS或PROP_DATASOURCE_JNDI_URL项的话,则会使用默认的连接池PoolingConnectionProvider。那PoolingConnectionProvider中使用的是什么连接池呢?我们可以看看PoolingConnectionProvider的描述和实现:

 1 /**
 2  * <p>
 3  * A <code>ConnectionProvider</code> implementation that creates its own
 4  * pool of connections.
 5  * </p>
 6  * 
 7  * <p>
 8  * This class uses C3PO (http://www.mchange.com/projects/c3p0/index.html) as
 9  * the underlying pool implementation.</p>
10  * 
11  * @see DBConnectionManager
12  * @see ConnectionProvider
13  * 
14  * @author Sharada Jambula
15  * @author James House
16  * @author Mohammad Rezaei
17  */
18 public class PoolingConnectionProvider implements ConnectionProvider

 

从类描述中我们就可以看出,该类使用的是C3P0的连接池技术,也就是说Quartz2.2.0默认使用的是C3P0连接池。然后我们看到该类实现了ConnectionProvider接口,首先看看ConnectionProvider的接口定义:

 1 /**
 2  * Implementations of this interface used by <code>DBConnectionManager</code>
 3  * to provide connections from various sources.
 4  * 
 5  * @see DBConnectionManager
 6  * @see PoolingConnectionProvider
 7  * @see JNDIConnectionProvider
 8  * @see org.quartz.utils.weblogic.WeblogicConnectionProvider
 9  * 
10  * @author Mohammad Rezaei
11  */
12 public interface ConnectionProvider {
13     /*
14      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15      * 
16      * Interface.
17      * 
18      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19      */
20 
21     /**
22      * @return connection managed by this provider
23      * @throws SQLException
24      */
25     Connection getConnection() throws SQLException;
26     
27     
28     void shutdown() throws SQLException;
29     
30     void initialize() throws SQLException;
31 }
View Code

 

从接口的描述可以知道,只需要实现该类,然后使用自定义的连接池技术就可以解决文中开头提到的问题了。

思路明确后,我们开始实现,我依照PoolingConnectionProvider的实现写了写了我自己的dbcp连接池的实现类,代码如下:

initialize方法:

 1 private void initialize(
 2         String dbDriver, 
 3         String dbURL, 
 4         String dbUser,
 5         String dbPassword, 
 6         int maxConnections, 
 7         int maxStatementsPerConnection, 
 8         String dbValidationQuery,
 9         boolean validateOnCheckout,
10         int idleValidationSeconds,
11         int maxIdleSeconds) throws SQLException, SchedulerException {
12         if (dbURL == null) {
13             throw new SQLException(
14                 "DBPool could not be created: DB URL cannot be null");
15         }
16         
17         if (dbDriver == null) {
18             throw new SQLException(
19                 "DBPool '" + dbURL + "' could not be created: " +
20                 "DB driver class name cannot be null!");
21         }
22         
23         if (maxConnections < 0) {
24             throw new SQLException(
25                 "DBPool '" + dbURL + "' could not be created: " + 
26                 "Max connections must be greater than zero!");
27         }
28 
29         
30         datasource = new BasicDataSource(); 
31         datasource.setDriverClassName(dbDriver);
32             
33         datasource.setUrl(dbURL); 
34         datasource.setUsername(dbUser); 
35         datasource.setPassword(dbPassword);
36         datasource.setMaxActive(maxConnections);
37         datasource.setMinIdle(1);
38         datasource.setMaxWait(maxIdleSeconds);
39         datasource.setMaxOpenPreparedStatements(maxStatementsPerConnection);
40         
41         if (dbValidationQuery != null) {
42             datasource.setValidationQuery(dbValidationQuery);
43             if(!validateOnCheckout)
44                 datasource.setTestOnBorrow(true);
45             else
46                 datasource.setTestOnReturn(true);
47             datasource.setTimeBetweenEvictionRunsMillis(idleValidationSeconds);
48         }
49     }
View Code

 

 1 public Connection getConnection() throws SQLException {
 2         return datasource.getConnection();
 3     }
 4     
 5     public void shutdown() throws SQLException {
 6         datasource.close();
 7     }    
 8 
 9     public void initialize() throws SQLException {
10         // do nothing, already initialized during constructor call
11         try {
12             this.initialize(this.driver, this.URL, this.user, this.password, 
13                     maxConnections, maxStatementsPerConnection, dbValidationQuery, 
14                     validateOnCheckout, idleValidationSeconds, maxIdleSeconds);
15         } catch (SchedulerException e) {
16             // TODO Auto-generated catch block
17             throw new SQLException(e);
18         }
19     }
View Code

 

然后在quartz.properties配置文件中配置org.quartz.dataSource.dbcpDS.connectionProvider.class属性,如下:

org.quartz.dataSource.dbcpDS.connectionProvider.class: com.dawning.cloudview.app.scheduleframe.service.scheduleframe.pool.DbcpConnectionProvider

启动OSGI环境,加载DBCP所需的bundle,然后测试。通过测试,发现能正常连上数据库。该方法可行。

转载于:https://www.cnblogs.com/softwindzy/p/3291187.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值