在activiti 动态配置 activiti 监听引擎启动和初始化(高级源码篇)一文中,我们讲解了如何动态的配置DataSource
当我们程序配置了DataSource,activiti 工作流引擎是如何打开数据库连接呢?有没有其他的方式配置数据库连接呢?
这一个章节主要讲解activiti 工作流引擎数据库连接的其他配置方式,以及底层如何封装连接,打开连接操作数据库。本章先从配置入手,了解常用的配置方法,以及引领大家阅读代码,使大家的印象更深刻,而不是只会配置,了解原理才是最重要的。
Datasource的配置如下所示:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/activiti" />
<property name="username" value="root" />
<property name="password" value="********" />
</bean>
工作流引擎的配置如下所示:
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="dataSource" ref=”dataSource” />
</bean>
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/activiti" />
<property name="username" value="root" />
<property name="password" value="********" />
</bean>
此种配置需要在server.xml中配置具体的数据源信息,具体的配置步骤如下:
1、在tomcat服务器的lib目录下加入数据库连接的驱动jar包
2、修改tomcat服务器的conf目录下server.xml配置文件
3、修改tomcat服务器的conf目录下server.xml配置文件
打开server.xml配置文件,可以看到里面自带的一个全局JNDI配置,如下图所示:
编辑server.xml文件,添加全局JNDI数据源配置,配置如下:
<Resource
name="jdbc/mysql"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"47
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"50 url="jdbc:mysql://192.168.1.144:3306/leadtest?useUnicode=true&characterEncoding=utf-8"/>
经过以上的两个步骤,全局JNDI数据源就配置好了,在上述的server.xml文件中,配置了MySQL数据库的全局JNDI数据源。
上面的配置完成了程序中怎么使用呢?
dataSourceJndiName
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="dataSourceJndiName" ref=”dataSourceJndiName” />
</bean>
上面的三种配置足够我们用了,那么这三种方式那种优先级比较高,换言之,那种方式的优先级比较高呢。下面我们就开始跟进源码看看activiti内核 是如何解析执行的吧。
首先进入org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl查找initDataSource()方法详细解析如下:
protected void initDataSource() { //首先判断dataSource是否存在看来这个优先级是最高的了。 if (dataSource==null) { //如果dataSource不存在则查找dataSourceJndiName是否配置了,如果jndi配置了使用。 if (dataSourceJndiName!=null) { try { //查找jndi配置信息。 dataSource = (DataSource) new InitialContext().lookup(dataSourceJndiName); } catch (Exception e) { throw new ActivitiException("couldn't lookup datasource from "+dataSourceJndiName+": "+e.getMessage(), e); } //如果上面的datasource和jndi都不存在就直接使用普通的方式 进行配置获取初始化PooledDataSource } else if (jdbcUrl!=null) { //任何一个为报错 if ( (jdbcDriver==null) || (jdbcUrl==null) || (jdbcUsername==null) ) { throw new ActivitiException("DataSource or JDBC properties have to be specified in a process engine configuration"); } //根据配置创建PooledDataSource 对象 PooledDataSource pooledDataSource = new PooledDataSource(ReflectUtil.getClassLoader(), jdbcDriver, jdbcUrl, jdbcUsername, jdbcPassword ); //下面是配置其他的数据库连接池信息 if (jdbcMaxActiveConnections > 0) { pooledDataSource.setPoolMaximumActiveConnections(jdbcMaxActiveConnections); } if (jdbcMaxIdleConnections > 0) { pooledDataSource.setPoolMaximumIdleConnections(jdbcMaxIdleConnections); } if (jdbcMaxCheckoutTime > 0) { pooledDataSource.setPoolMaximumCheckoutTime(jdbcMaxCheckoutTime); } if (jdbcMaxWaitTime > 0) { pooledDataSource.setPoolTimeToWait(jdbcMaxWaitTime); } if (jdbcPingEnabled == true) { pooledDataSource.setPoolPingEnabled(true); if (jdbcPingQuery != null) { pooledDataSource.setPoolPingQuery(jdbcPingQuery); } pooledDataSource.setPoolPingConnectionsNotUsedFor(jdbcPingConnectionNotUsedFor); } if (jdbcDefaultTransactionIsolationLevel > 0) { pooledDataSource.setDefaultTransactionIsolationLevel(jdbcDefaultTransactionIsolationLevel); } dataSource = pooledDataSource; } if (dataSource instanceof PooledDataSource) { //调用forceCloseAll方法,如果不调用Ibatis 数据库池子拿不到上面的数据库配置连接信息 ((PooledDataSource)dataSource).forceCloseAll(); } } //如果程序没有配置databaseType 数据库类型则activiti自己根据连接字符串打开一次请求获取类型 if (databaseType == null) { initDatabaseType(); } }
initDatabaseType()详细的方法如下:
//说白了就是反射数据库拿到元数据信息进行判断 这里最好配置一次可以优化的地方,没有配置的话要打开一次数据库连接
public void initDatabaseType() { Connection connection = null; try { connection = dataSource.getConnection(); //根据连接获取到元数据信息 DatabaseMetaData databaseMetaData = connection.getMetaData(); //获取到数据库生产厂商信息 String databaseProductName = databaseMetaData.getDatabaseProductName(); log.debug("database product name: '{}'", databaseProductName); //因为市面上的数据库库厂商是固定的所以这里一次性加载到内存然后根据查找的数据库厂商匹配 databaseType = databaseTypeMappings.getProperty(databaseProductName); if (databaseType==null) { throw new ActivitiException("couldn't deduct database type from database product name '"+databaseProductName+"'"); } } catch (SQLException e) { } finally { try { //上面打开了连接所以这里释放了连接 if (connection!=null) { connection.close(); } } catch (SQLException e) { log.error("Exception while closing the Database connection", e); } } }
数据库datatype与数据库厂商的映射如下:
public static final String DATABASE_TYPE_H2 = "h2"; public static final String DATABASE_TYPE_HSQL = "hsql"; public static final String DATABASE_TYPE_MYSQL = "mysql"; public static final String DATABASE_TYPE_ORACLE = "oracle"; public static final String DATABASE_TYPE_POSTGRES = "postgres"; public static final String DATABASE_TYPE_MSSQL = "mssql"; public static final String DATABASE_TYPE_DB2 = "db2"; protected static Properties getDefaultDatabaseTypeMappings() { Properties databaseTypeMappings = new Properties(); databaseTypeMappings.setProperty("H2", DATABASE_TYPE_H2); databaseTypeMappings.setProperty("HSQL Database Engine", DATABASE_TYPE_HSQL); databaseTypeMappings.setProperty("MySQL", DATABASE_TYPE_MYSQL); databaseTypeMappings.setProperty("Oracle", DATABASE_TYPE_ORACLE); databaseTypeMappings.setProperty("PostgreSQL", DATABASE_TYPE_POSTGRES); databaseTypeMappings.setProperty("Microsoft SQL Server", DATABASE_TYPE_MSSQL); databaseTypeMappings.setProperty(DATABASE_TYPE_DB2,DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/NT",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/NT64",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2 UDP",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/LINUX",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/LINUX390",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/LINUXX8664",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/LINUXZ64",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/LINUXPPC64",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/400 SQL",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/6000",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2 UDB iSeries",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/AIX64",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/HPUX",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/HP64",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/SUN",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/SUN64",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/PTX",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2/2",DATABASE_TYPE_DB2); databaseTypeMappings.setProperty("DB2 UDB AS400", DATABASE_TYPE_DB2); return databaseTypeMappings; }
上面详细的总结了activiti 工作流引擎常用的数据库连接配置,以及优先级的问题,数据库databaseType可以优化性能。
具体的封装自己的datasource可以参考mysql数据库连接池使用(二)实现自己的数据库连接池文章