使用 spring 集成 dbcp 数据库连接池到 Wowza 插件
对于 Wowza 扩展插件,很可能需要连接数据库进行一些持久化查询操作,而且也很有可能把各种业务逻辑 bean 进行集中管理起来。本文结合集成 dbcp 数据库连接池到 Wowza 插件的案例,顺带介绍 spring 和 Wowza 的集成。本文示例在 Wowza Streaming Engine 4.0.1 下执行成功。
1. 准备依赖包
本文示例数据库为 MySQL,持久化框架为 iBATIS,spring 版本是为 3.1.2.RELEASE,所以相关依赖包如下所示:
把这些包都考到 Wowza 安装目录下的 lib 文件夹中。
2. 新建服务监听类
Eclipse 下新建一个 Wowza 插件项目 defonds-server-module。关于 Eclipse 安装 Wowza IDE 插件,以及插件项目的建立前面博客已有介绍,在此不再赘述。
项目建立以后,新建 com.defonds.wms.module.server 包,然后右击该包 -> New -> Other... -> 选择 Wowza Media Server ServerListener Class -> Next -> 对话框中输入你的类名 -> 点击 Finish 完成服务监听类的创建。
新建好的类 DefondsWowzaServerListener 源码如下:
3. 将新建的监听类注册到 Wowza
使用文本编辑器打开 Wowza 安装目录下的 conf 文件夹中的 Server.xml,在 ServerListeners 标签下添加以下内容:
如下图所示
4. 测试用数据初始化
MySQL db 下新建数据库 rtp,然后执行以下语句:
5. 数据库配置文件的添加
src 下新建 config.properties 并编辑其内容如下
6. iBATIS 支持
新建包 com.defonds.wms.module.common.dao 并在其下新建类 BaseDao、BaseDaoImpl,新建包 com.defonds.wms.module.common.service 并在其下新建类 BaseService。BaseDao 源码如下:
BaseDaoImpl 源码如下:
BaseService 源码如下:
然后在 src 下新建 sqlMapConfig.xml 并编辑其内容如下:
最后在 src 下新建 config.xml 并编辑其内容如下:
7. 测试类的添加
新建包 com.defonds.wms.module.test.entity 并在其下新建实体类 Config(对应于第四步的表),新建包 com.defonds.wms.module.test.service 并在其下新建测试类 TestService、TestServiceImpl。Config 源码如下:
TestService 源码:
TestServiceImpl 源码:
8. spring 支持
新建包 com.defonds.wms.module.utils.spring,在包中新建类 ApplicationContextUtils 并编辑其源码如下:
在 src 下新建 spring-context.xml 并编辑其内容如下:
然后再回到 DefondsWowzaServerListener 类,在 onServerInit 中添加代码如下:
至此,所有准备工作就绪。整个项目结构如下图所示:
所有其他监听类通过对 ApplicationContextUtils 的调用,即可对 spring 管理的对象进行访问了。
测试
在任何插件类中加入如下代码:
Eclipse 下启动 Wowza(如何启动清参阅《 使用 Wowza IDE 开发第一个 Wowza 服务器扩展应用 -- 监控直播频道》)控制台打印结果如下:
DefondsWowzaServerListener-onServerInit-strFromContext=201403251535Hello World
INFO server comment - onServerInit
TestServiceImpl--201403251711-------
javax.net.ssl.truststore:/home/cloud/lyh/relaystore.jks
javax.net.ssl.truststorepassword:123456
本资源源码已上传 csdn 资源,有兴趣的朋友可以去下载一下,链接地址: http://download.csdn.net/detail/defonds/7098633。
1. 准备依赖包
本文示例数据库为 MySQL,持久化框架为 iBATIS,spring 版本是为 3.1.2.RELEASE,所以相关依赖包如下所示:
把这些包都考到 Wowza 安装目录下的 lib 文件夹中。
2. 新建服务监听类
Eclipse 下新建一个 Wowza 插件项目 defonds-server-module。关于 Eclipse 安装 Wowza IDE 插件,以及插件项目的建立前面博客已有介绍,在此不再赘述。
项目建立以后,新建 com.defonds.wms.module.server 包,然后右击该包 -> New -> Other... -> 选择 Wowza Media Server ServerListener Class -> Next -> 对话框中输入你的类名 -> 点击 Finish 完成服务监听类的创建。
新建好的类 DefondsWowzaServerListener 源码如下:
package com.defonds.wms.module.server;
import com.wowza.wms.logging.*;
import com.wowza.wms.server.*;
public class DefondsWowzaServerListener implements IServerNotify2 {
public void onServerConfigLoaded(IServer server) {
WMSLoggerFactory.getLogger(null).info("onServerConfigLoaded");
}
public void onServerCreate(IServer server) {
WMSLoggerFactory.getLogger(null).info("onServerCreate");
}
public void onServerInit(IServer server) {
WMSLoggerFactory.getLogger(null).info("onServerInit");
}
public void onServerShutdownStart(IServer server) {
WMSLoggerFactory.getLogger(null).info("onServerShutdownStart");
}
public void onServerShutdownComplete(IServer server) {
WMSLoggerFactory.getLogger(null).info("onServerShutdownComplete");
}
}
3. 将新建的监听类注册到 Wowza
使用文本编辑器打开 Wowza 安装目录下的 conf 文件夹中的 Server.xml,在 ServerListeners 标签下添加以下内容:
<ServerListener>
<BaseClass>com.defonds.wms.module.server.DefondsWowzaServerListener</BaseClass>
</ServerListener>
如下图所示
4. 测试用数据初始化
MySQL db 下新建数据库 rtp,然后执行以下语句:
-- ----------------------------
-- Table structure for `config`
-- ----------------------------
DROP TABLE IF EXISTS `config`;
CREATE TABLE `config` (
`conId` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`value` text,
`value_type` int(11) DEFAULT '0',
`description` varchar(256) DEFAULT NULL,
`create_time` datetime NOT NULL,
PRIMARY KEY (`conId`),
UNIQUE KEY `Index_1` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of config
-- ----------------------------
INSERT INTO `config` VALUES ('1', 'javax.net.ssl.truststore', '/home/cloud/lyh/relaystore.jks', '0', 'relaystore.jks文件绝对路径', '2012-11-15 16:01:47');
INSERT INTO `config` VALUES ('2', 'javax.net.ssl.truststorepassword', '123456', '0', 'relaystore.jks密码', '2012-11-15 16:01:47');
5. 数据库配置文件的添加
src 下新建 config.properties 并编辑其内容如下
mysql.db=172.21.0.114:3306/rtp
#mysql.db=172.21.0.114:3306/rtp
runJob=false
6. iBATIS 支持
新建包 com.defonds.wms.module.common.dao 并在其下新建类 BaseDao、BaseDaoImpl,新建包 com.defonds.wms.module.common.service 并在其下新建类 BaseService。BaseDao 源码如下:
package com.defonds.wms.module.common.dao;
import java.util.List;
import java.util.Map;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import com.ibatis.sqlmap.client.event.RowHandler;
public interface BaseDao {
public <T> T execute(SqlMapClientCallback action) throws DataAccessException;
public <T> T queryForObject(String statementName) throws DataAccessException;
public <T> T queryForObject(final String statementName, final Object parameterObject) throws DataAccessException;
public <T> T queryForObject(final String statementName, final Object parameterObject, final Object resultObject) throws DataAccessException;
public List<?> queryForList(String statementName) throws DataAccessException;
public List<?> queryForList(final String statementName, final Object parameterObject) throws DataAccessException;
public List<?> queryForList(String statementName, int skipResults, int maxResults)throws DataAccessException;
public List<?> queryForList(final String statementName, final Object parameterObject, final int skipResults, final int maxResults) throws DataAccessException;
public void queryWithRowHandler(String statementName, RowHandler rowHandler)throws DataAccessException;
public void queryWithRowHandler( final String statementName, final Object parameterObject, final RowHandler rowHandler) throws DataAccessException;
public Map<?,?> queryForMap( final String statementName, final Object parameterObject, final String keyProperty) throws DataAccessException;
public Map<?,?> queryForMap( final String statementName, final Object parameterObject, final String keyProperty, final String valueProperty) throws DataAccessException;
public <T> T insert(String statementName) throws DataAccessException;
public <T> T insert(final String statementName, final Object parameterObject) throws DataAccessException;
public int update(String statementName) throws DataAccessException;
public int update(final String statementName, final Object parameterObject) throws DataAccessException;
public void update(String statementName, Object parameterObject, int requiredRowsAffected) throws DataAccessException;
public int delete(String statementName) throws DataAccessException;
public int delete(final String statementName, final Object parameterObject) throws DataAccessException;
public void delete(String statementName, Object parameterObject, int requiredRowsAffected) throws DataAccessException;
public <T> void insertBatch(final String statementName, final List<T> list);
public <T> int updateBatch(final String statementName, final List<T> list);
}
BaseDaoImpl 源码如下:
package com.defonds.wms.module.common.dao;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import com.ibatis.sqlmap.client.SqlMapExecutor;
import com.ibatis.sqlmap.client.event.RowHandler;
import com.ibatis.sqlmap.engine.execution.BatchException;
import com.ibatis.sqlmap.engine.execution.BatchResult;
public class BaseDaoImpl extends SqlMapClientDaoSupport implements BaseDao {
public void test(){
//SqlMapClientTemplate ddd = super.getSqlMapClientTemplate();
}
private static final Log LOG = LogFactory.getLog(BaseDaoImpl.class);
@SuppressWarnings("unchecked")
public <T> T execute(SqlMapClientCallback action) throws DataAccessException {
return (T) getSqlMapClientTemplate().execute(action);
}
@SuppressWarnings("unchecked")
public <T> T queryForObject(String statementName) throws DataAccessException {
return (T) getSqlMapClientTemplate().queryForObject(statementName);
}
@SuppressWarnings("unchecked")
public <T> T queryForObject(final String statementName, final Object parameterObject) throws DataAccessException {
return (T) getSqlMapClientTemplate().queryForObject(statementName, parameterObject);
}
@SuppressWarnings("unchecked")
public <T> T queryForObject(final String statementName, final Object parameterObject, final Object resultObject) throws DataAccessException {
return (T) getSqlMapClientTemplate().queryForObject(statementName, parameterObject, resultObject);
}
public List<?> queryForList(String statementName) throws DataAccessException {
return queryForList(statementName, null);
}
public List<?> queryForList(final String statementName, final Object parameterObject) throws DataAccessException {
return getSqlMapClientTemplate().queryForList(statementName, parameterObject);
}
public List<?> queryForList(String statementName, int skipResults, int maxResults)throws DataAccessException {
return queryForList(statementName, null, skipResults, maxResults);
}
public List<?> queryForList(final String statementName, final Object parameterObject, final int skipResults, final int maxResults) throws DataAccessException {
return getSqlMapClientTemplate().queryForList(statementName, parameterObject, skipResults, maxResults);
}
public void queryWithRowHandler(String statementName, RowHandler rowHandler)throws DataAccessException {
queryWithRowHandler(statementName, null, rowHandler);
}
public void queryWithRowHandler( final String statementName, final Object parameterObject, final RowHandler rowHandler) throws DataAccessException {
getSqlMapClientTemplate().queryWithRowHandler(statementName, parameterObject, rowHandler);
}
public Map<?,?> queryForMap( final String statementName, final Object parameterObject, final String keyProperty) throws DataAccessException {
return getSqlMapClientTemplate().queryForMap(statementName, parameterObject, keyProperty);
}
public Map<?,?> queryForMap( final String statementName, final Object parameterObject, final String keyProperty, final String valueProperty) throws DataAccessException {
return getSqlMapClientTemplate().queryForMap(statementName, parameterObject, keyProperty, valueProperty);
}
public <T> T insert(String statementName) throws DataAccessException {
return (T) getSqlMapClientTemplate().insert(statementName, null);
}
@SuppressWarnings("unchecked")
public <T> T insert(final String statementName, final Object parameterObject) throws DataAccessException {
return (T) getSqlMapClientTemplate().insert(statementName, parameterObject);
}
public int update(String statementName) throws DataAccessException {
return update(statementName, null);
}
public int update(final String statementName, final Object parameterObject) throws DataAccessException {
Integer result = (Integer) execute(new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
return new Integer(executor.update(statementName, parameterObject));
}
});
return result.intValue();
}
public void update(String statementName, Object parameterObject, int requiredRowsAffected)
throws DataAccessException {
int actualRowsAffected = update(statementName, parameterObject);
if (actualRowsAffected != requiredRowsAffected) {
throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
statementName, requiredRowsAffected, actualRowsAffected);
}
}
public int delete(String statementName) throws DataAccessException {
return delete(statementName, null);
}
public int delete(final String statementName, final Object parameterObject)
throws DataAccessException {
Integer result = (Integer) execute(new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
return new Integer(executor.delete(statementName, parameterObject));
}
});
return result.intValue();
}
public void delete(String statementName, Object parameterObject, int requiredRowsAffected) throws DataAccessException {
int actualRowsAffected = delete(statementName, parameterObject);
if (actualRowsAffected != requiredRowsAffected) {
throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
statementName, requiredRowsAffected, actualRowsAffected);
}
}
public <T> int updateBatch(final String statementName, final List<T> list) {
if(list == null || list.isEmpty()){
return 0;
}
SqlMapClientCallback callback = new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
executor.startBatch();
for (Object obj : list) {
executor.update(statementName, obj);
}
try {
return executor.executeBatchDetailed();
} catch (BatchException e) {
LOG.error(e.getMessage(), e);
throw new SQLException("Batch update failed!");
}
}
};
List<BatchResult> retList = (List<BatchResult>) getSqlMapClientTemplate().execute(callback);
return batchResult(retList);
}
/**
* 从批处理结果返回处理成功的记录数
* @param batchResultList
* @return count
*/
private int batchResult(List<BatchResult> batchResultList) {
int count = 0;
if (batchResultList != null && !batchResultList.isEmpty()) {
BatchResult result = batchResultList.get(0);
if (result != null) {
for (int i : result.getUpdateCounts()) {
if (i == java.sql.Statement.SUCCESS_NO_INFO) {
count++;
} else {
count += i;
}
}
}
}
return count;
}
public <T> void insertBatch(final String statementName, final List<T> list) {
getSqlMapClientTemplate().execute(
new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
executor.startBatch();
for (int i = 0; i < list.size(); i++) {
T t = (T)list.get(i);
executor.insert(statementName, t);
if (i%50 == 0) {
executor.executeBatch();
}
}
executor.executeBatch();
return null;
}
});
}
}
BaseService 源码如下:
package com.defonds.wms.module.common.service;
import com.defonds.wms.module.common.dao.BaseDao;
public class BaseService {
private BaseDao baseDao;
public BaseDao getBaseDao() {
return baseDao;
}
public void setBaseDao(BaseDao baseDao) {
this.baseDao = baseDao;
}
}
然后在 src 下新建 sqlMapConfig.xml 并编辑其内容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings cacheModelsEnabled="true" enhancementEnabled="true" useStatementNamespaces="true"/>
<sqlMap resource="config.xml"/><!-- config Related -->
</sqlMapConfig>
最后在 src 下新建 config.xml 并编辑其内容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="config">
<resultMap id="configData" class="com.defonds.wms.module.test.entity.Config">
<result property="conId" column="conId"/>
<result property="name" column="name" />
<result property="value" column="value"/>
<result property="valueType" column="value_type"/>
<result property="description" column="description"/>
<result property="createTime" column="create_time" />
</resultMap>
<select id="getAllConfigs" resultMap="configData">
SELECT * FROM config
</select>
</sqlMap>
7. 测试类的添加
新建包 com.defonds.wms.module.test.entity 并在其下新建实体类 Config(对应于第四步的表),新建包 com.defonds.wms.module.test.service 并在其下新建测试类 TestService、TestServiceImpl。Config 源码如下:
package com.defonds.wms.module.test.entity;
import java.io.Serializable;
import java.util.Date;
/** @author Hibernate CodeGenerator */
public class Config implements Serializable {
private static final long serialVersionUID = -5401525190715090496L;
/** identifier field */
private int conId;
/** nullable persistent field */
private String name;
/** persistent field */
private String value;
/** nullable persistent field */
private int valueType;
/** nullable persistent field */
private String description;
/** persistent field */
private Date createTime;
public int getConId() {
return this.conId;
}
public void setConId(int conId) {
this.conId = conId;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getCreateTime() {
return this.createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public int getValueType() {
return valueType;
}
public void setValueType(int valueType) {
this.valueType = valueType;
}
}
TestService 源码:
package com.defonds.wms.module.test.service;
public interface TestService {
public void test();
}
TestServiceImpl 源码:
package com.defonds.wms.module.test.service;
import java.util.Iterator;
import java.util.List;
import com.defonds.wms.module.test.entity.Config;
import com.defonds.wms.module.common.service.BaseService;
public class TestServiceImpl extends BaseService implements TestService {
@Override
public void test() {
System.out.println("TestServiceImpl--201403251711-------");
List<Config> result=(List<Config>)getBaseDao().queryForList("config.getAllConfigs");
Iterator it = result.iterator();
while (it.hasNext()) {
Config cf = (Config) it.next();
System.out.println(cf.getName() + ":" + cf.getValue());
}
}
}
8. spring 支持
新建包 com.defonds.wms.module.utils.spring,在包中新建类 ApplicationContextUtils 并编辑其源码如下:
package com.defonds.wms.module.utils.spring;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
在 src 下新建 spring-context.xml 并编辑其内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/tx/spring-aop-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"
default-autowire="byName">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations"
value="classpath:config.properties" />
</bean>
<!-- ibatis config -->
<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://${mysql.db}?useUnicode=true&characterEncoding=utf-8" />
<property name="username" value="dev" />
<property name="password" value="dev" />
<property name="validationQuery" value="select 1" />
<property name="testWhileIdle" value="true" />
<property name="minEvictableIdleTimeMillis" value="1800000" />
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
scope="singleton">
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate"
depends-on="transactionManager">
<property name="sqlMapClient" ref="sqlMapClient" />
</bean>
<!-- Instruct Spring to perform declarative transaction management automatically
on annotated classes. -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="baseDao" class="com.defonds.wms.module.common.dao.BaseDaoImpl"
abstract="false" lazy-init="true">
<property name="sqlMapClientTemplate" ref="sqlMapClientTemplate" />
</bean>
<bean id="baseService" class="com.defonds.wms.module.common.service.BaseService"
abstract="true" lazy-init="true">
<property name="baseDao" ref="baseDao" />
</bean>
<!-- wowza related -->
<bean id="applicationContextUtils"
class="com.defonds.wms.module.utils.spring.ApplicationContextUtils"></bean>
<bean id="strHelloWorld" class="java.lang.String">
<constructor-arg value="201403251535Hello World" />
</bean>
<!-- test related -->
<bean id="testService" class="com.defonds.wms.module.test.service.TestServiceImpl" parent="baseService" scope="singleton" />
</beans>
然后再回到 DefondsWowzaServerListener 类,在 onServerInit 中添加代码如下:
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml"); // init here
ApplicationContextAware aca = (ApplicationContextAware) context.getBean("applicationContextUtils"); // save this context instance to utils
aca.setApplicationContext(context);
至此,所有准备工作就绪。整个项目结构如下图所示:
所有其他监听类通过对 ApplicationContextUtils 的调用,即可对 spring 管理的对象进行访问了。
测试
在任何插件类中加入如下代码:
/**
* test
*/
ApplicationContext appCtx = ApplicationContextUtils.getApplicationContext();
// get any bean
String strFromContext = (String) appCtx.getBean("strHelloWorld");
System.out.println("DefondsWowzaServerListener-onServerInit-strFromContext=" + strFromContext);
WMSLoggerFactory.getLogger(null).info("onServerInit");
// get db data
TestService testService = (TestService) appCtx.getBean("testService");
testService.test();
Eclipse 下启动 Wowza(如何启动清参阅《 使用 Wowza IDE 开发第一个 Wowza 服务器扩展应用 -- 监控直播频道》)控制台打印结果如下:
DefondsWowzaServerListener-onServerInit-strFromContext=201403251535Hello World
INFO server comment - onServerInit
TestServiceImpl--201403251711-------
javax.net.ssl.truststore:/home/cloud/lyh/relaystore.jks
javax.net.ssl.truststorepassword:123456
打印结果的最后两行正是我们数据库中的记录,使用 spring 集成 dbcp 数据库连接池到 Wowza 插件成功。
注意
如果你有多个 Wowza 插件项目,不需要每个插件都重复集成各自的 spring,部署好了一个,集成进来的 spring context 就是公用的!如果你坚持要为每个插件项目集成单独的一个 spring,请注意每个 contxt xml 配置名不要一致,否则 Wowza 只会加载其中一个,造成其他插件定义的 bean 不会初始化而造成空指针错误。
后记本资源源码已上传 csdn 资源,有兴趣的朋友可以去下载一下,链接地址: http://download.csdn.net/detail/defonds/7098633。