要将iBatis集成到OSGi环境中,主要完成的就是各bundle中的sqlmap配置文件的动态加载与移除。而iBatis的api中并没有提供直接移除sqlmap中statement的api,而且在iBatis中也并没有将statement按照namespace来存放,而仅仅是将namespace作为statement的id的一个前缀。所以我们首先要做的就是对iBatis的代码进行改造,以达到能动态添加和移除sqlmap的功能(本文章中所用到的是iBatis 2.3.4)
此改造是在Spring的SqlMapClientFactoryBean 的基础上进行,因为SqlMapClientFactoryBean 已经基本实现了sqlmap文件的动态增加,首先我们编写一个类继承SqlMapClientFactoryBean,然后在Spring DM的配置文件中将BundleContext注入到这个类中(Spring DM的配置过程可以到百度上面搜索),如下:
<bean id="sqlMapClient" class="com.yinhai.ibatis.ext.DySqlMapClientFactoryBean">
<property name="configLocation" value="classpath:sql-map-config.xml" />
<property name="context" ref="bundleContext"/>
<property name="dataSource" ref="dataSource" />
</bean>
在setContext方法中来处理bundle中的配置文件,也可以自己再写一个init方法
public void setContext(BundleContext context) {
this.context = context;
Bundle[] bundles = context.getBundles();
for (Bundle bundle : bundles) {
if (bundle.getState() ==Bundle.ACTIVE) {
//SQLMAP_PATTERN为sqlMap的后缀名,此处我用的是"*SqlMap.xml"
Enumeration<URL> enu = bundle.findEntries("/", SQLMAP_PATTERN,
true);
if (enu != null) {
while (enu.hasMoreElements()) {
resourceList.add(new UrlResource(enu.nextElement()));
}
}
}
}
//设置已经加载的Bundle中的sqlmap文件
setMappingLocations(resourceList.toArray(new Resource[resourceList.size()]));
context.addBundleListener(new BundleListener() {
@Override
public void bundleChanged(BundleEvent event) {
if (event.getType() == BundleEvent.STARTED) {
addSqlmapsFromBundle(event.getBundle());
} else if (event.getType() == BundleEvent.STOPPED) {
removeSqlMapsFromBundle(event.getBundle());
}
}
});
}
此方法中已经将mappingLocations设置好了,接下来就是将这些sqlmap配置文件加载到iBatis中,需要重写方法
protected SqlMapClient buildSqlMapClient(Resource[] configLocations,
Resource[] mappingLocations, Properties properties)
throws IOException
Spring的实现如下:
protected SqlMapClient buildSqlMapClient(Resource[] configLocations,
Resource[] mappingLocations, Properties properties)
throws IOException {
if (ObjectUtils.isEmpty(configLocations)) {
throw new IllegalArgumentException(
"At least 1 'configLocation' entry is required");
}
SqlMapClient client = null;
SqlMapConfigParser configParser = new SqlMapConfigParser();
InputStream is;
for (Resource configLocation : configLocations) {
is = configLocation.getInputStream();
try {
client = configParser.parse(is, properties);
} catch (RuntimeException ex) {
throw new NestedIOException("Failed to parse config resource: "
+ configLocation, ex.getCause());
}
}
if (mappingLocations != null) {
//SqlMapParser对象为局部变量,由于后面需要用到,所以应将它设置成类的成员变量。
SqlMapParser mapParser = SqlMapParserFactory
.createSqlMapParser(configParser);
for (Resource mappingLocation : mappingLocations) {
try {
mapParser.parse(mappingLocation.getInputStream());
} catch (NodeletException ex) {
throw new NestedIOException(
"Failed to parse mapping resource: "
+ mappingLocation, ex);
}
}
}
return client;
}
修改后的代码如下:
private SqlMapParser mapParser = null;
....
protected SqlMapClient buildSqlMapClient(Resource[] configLocations,
Resource[] mappingLocations, Properties properties)
throws IOException {
if (ObjectUtils.isEmpty(configLocations)) {
throw new IllegalArgumentException(
"At least 1 'configLocation' entry is required");
}
SqlMapClient client = null;
SqlMapConfigParser configParser = new SqlMapConfigParser();
for (int i = 0; i < configLocations.length; i++) {
InputStream is = configLocations[i].getInputStream();
try {
client = configParser.parse(is, properties);
} catch (RuntimeException ex) {
throw new NestedIOException("Failed to parse config resource: "
+ configLocations[i], ex.getCause());
}
}
mapParser = SqlMapParserFactory.createSqlMapParser(configParser);
client = new DySqlMapClient(client, mapParser, configParser,
configLocations);
if (mappingLocations != null) {
for (Resource mappingLocation : mappingLocations) {
try {
mapParser.parse(mappingLocation.getInputStream());
} catch (NodeletException ex) {
throw new NestedIOException(
"Failed to parse mapping resource: "
+ mappingLocation, ex);
}
}
}
return client;
}
动态增加SqlMap配置
上面完成了对已经启动的bundle中sqlmap文件的加载,而在之后启动的bundle则在addSqlmapsFromBundle方法中处理
private void addSqlmapsFromBundle(Bundle bundle){
Enumeration<URL> enu = bundle.findEntries("/",
SQLMAP_PATTERN, true);
logger.info("添加sqlMaps配置");
if (enu != null) {
while (enu.hasMoreElements()) {
try {
DySqlMapClientFactoryBean.this.mapParser
.parse(new UrlResource(enu
.nextElement())
.getInputStream());
} catch (NodeletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这儿就用到了刚才存放在类中的成员变量mapParser, 此Parser就是正在使用的那一个,所以通过它可以动态向正在运行的iBatis中加入sqlMap配置。
动态删除SqlMap配置
之前说过,由于iBatis的api并没有提供直接的支持,所以只能找到iBatis把statement存放在哪儿,然后通过反射或者修改源代码的方式将api暴露出来。跟踪iBatis的源码,可以发现,所有sqlMap中的statement都存放在SqlMapExecutorDelegate 类中的mappedStatements 变量中,此变量为一个HashMap,key为statement的id加上namespace(如果开启了namespace的话,所以我们只要将这个HashMap暴露出来,就一切搞定,所以要先修改这个类,将mappedStatements 暴露出来,而这个类本身又是存放在XmlParserState 对象的config 对象中,XmlParserState 类则是直接和我们上面的mapParser 关联,但mapParser 并没有提供取得XmlParserState 的方法,Spring是直接通过反射得到的,我们可以直接修改源代码,加一个方法,SqlMapParser 代码中增加如下代码:
/**
* FIXME 增加get方法,取得state,以便动态移除statement。
* @return
*/
public XmlParserState getState(){
return state;
}
SqlMapExecutorDelegate 代码增加
public Map getMappedStatement() {
return mappedStatements;
}
这时我们就可以在DySqlMapClientFactoryBean中来移除Sqlmap了
/**
* 移除bundle中sqlMap对应的配置
* @param bundle
*/
private void removeSqlMapsFromBundle(Bundle bundle) {
Enumeration<URL> enu = bundle.findEntries("/",SQLMAP_PATTERN, true);
if (enu != null) {
Map statements = ((DySqlMapExecutorDelegate) mapParser.getState()
.getConfig().getDelegate()).getDelegate()
.getMappedStatement();
Map resultMaps = ((DySqlMapExecutorDelegate) mapParser.getState()
.getConfig().getDelegate()).getDelegate().getResultMap();
while (enu.hasMoreElements()) {
InputStream is = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
is = enu.nextElement().openStream();
SqlMapConfigUtils.copy(is, bos);
// 移除statement
List<String> states = SqlMapConfigUtils
.readSqlMap(new ByteArrayInputStream(bos
.toByteArray()));
for (String id : states) {
synchronized (statements) {
if (statements.containsKey(id)) {
statements.remove(id);
logger.info("移除id为" + id + "的statement");
}
}
}
// 移除statement
List<String> results = SqlMapConfigUtils
.readResultMap(new ByteArrayInputStream(bos
.toByteArray()));
for (String id : results) {
synchronized (resultMaps) {
if (resultMaps.containsKey(id)) {
resultMaps.remove(id);
logger.info("移除id为" + id + "的resultMap");
}
}
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
} catch (JDOMException e) {
logger.error(e.getMessage(), e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
bos = null;
}
}
}
}
相关推荐
描述中提到"一个osgi集成ibatis的例子,我也是在网上下载的",这表明这个压缩包可能包含了一个完整的项目,用于演示如何在OSGi环境下配置和使用iBatis。这通常包括了配置文件、服务接口、实现类以及必要的依赖库。 ...
在这个“osgi数据库连接demo”中,我们将探讨如何在OSGi环境中配置C3P0作为Oracle数据库连接池,并集成iBATIS作为数据访问层。 首先,C3P0是一个开源的JDBC连接池,它提供了一些额外的功能,如自动管理数据库连接、...
- 支持多种ORM工具,如JDO、Hibernate和iBatis SQL Map。 - 通过统一的事务管理和异常处理机制,使得ORM工具之间的切换变得简单。 6. **Spring Web**: - 为基于Web的应用程序提供了一个强大的上下文环境。 - ...
相比之下,iBatis虽然也可以与Spring框架集成,但在集成的深度和广度上不如Hibernate。 9. **与JBoss等容器的兼容性**:由于Hibernate遵循JSR 250规范,因此它能够很好地与其他Java EE容器(如JBoss)进行集成。...
标题中的“OSGI研究笔记1 - Equinox ServletBridge模式下调用Datasource”表明了这篇文章将探讨如何在OSGI(Open Service Gateway ...对于理解OSGI环境下的服务集成和数据库访问,这个主题具有很高的实践价值。
8. **Spring OSGi**:提供了对OSGi(Open Service Gateway Initiative)服务的集成,使得Spring应用能在OSGi容器中运行。 9. **Spring Test**:这个模块提供了对Spring应用的测试支持,包括单元测试和集成测试,...
- 组件框架:用于对象关系映射,如Hibernate、iBatis和Cayenne。 - 服务框架:面向服务计算的模型,如语义网服务框架。 - 开发框架:用于构建富客户端开发工具,如Eclipse、NetBeans和OSGi。 3. 网络应用框架(WAF...
4. **对象/关系映射(ORM Module)**:Spring集成了多种ORM框架,如JDO、Hibernate和iBatis,使得开发者能将这些ORM技术与Spring的其他功能(如事务管理)结合使用,提高了代码的可维护性和可测试性。 5. **面向切面...
spring 3.0已经全面支持OSGi了。 各发行包的大致描述如下: org.springframework.asm-3.0.0.M4.jar: 提供对ASM(一个字节码框架)的简单封装 org.springframework.expression-3.0.0.M4.jar: spring表达式语言 ...
2. **数据库集成**:OpenStaff 使用数据库来存储员工数据,可能包括 MySQL 或其他关系型数据库。数据库的配置和操作是通过 iBatis 这样的持久层框架完成的,它简化了 SQL 查询的编写和执行。 3. **iBatis 配置**:...
- **Hibernate/Ibatis/JPA**:这些工具提供了对象关系映射(ORM)的支持,简化了数据库操作。 - **P2:扩展框架** - **OSGi**:为Java平台定义了一个动态模块系统,Equinox 和 SpringDM 是其中两个实现。 - **SOA...
可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI所需的全部类,UI方面的用来与模板(Templating)引擎如 Velocity、FreeMarker、JasperReports集成的类,以及校验Validation方面的相关类。...
- **WebService、SOA、SCA、ESB、OSGI、EAI**:构建服务化的企业级应用。 综上所述,从Java程序员到Java EE系统架构师,不仅涵盖了Java语言的基础和高级特性,还包括了Web开发、企业级应用框架、分布式计算等多个...