`
liwei113114
  • 浏览: 14374 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

OSGi集成iBatis

    博客分类:
  • OSGi
 
阅读更多
       要将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_PATTERNtrue);
        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_PATTERNtrue);
        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;
                }
            }
        }
    }
 
2
3
分享到:
评论
6 楼 zpcsa 2014-08-19  
你好,代码没调试成功,能把您的代码发一份给我吗,我的邮箱QQ:116607233@qq.com
5 楼 liwei113114 2013-11-22  
王逝天涯 写道
如果在sqlMapConfig 文件中sqlMap resource 是从另外一个bundle中引入SqlMap.xml,应该做如何处理?

最好不要在SqlMapConfig中引入sqlMap文件,而是直接调用api来解析sqlMap文件,你可以在iBatis的bundle中监听其它bundle的生命周期,当一个插件启动时,就到里面去找有没有sqlMap文件,有的话就解析。
4 楼 王逝天涯 2013-11-21  
如果在sqlMapConfig 文件中sqlMap resource 是从另外一个bundle中引入SqlMap.xml,应该做如何处理?
3 楼 liwei113114 2013-06-08  
lymalf 写道
你可以把ibatis发布成一个服务。这样其他的bundle就都可以调用了。

对,我就是这样想的,其实还可以上层加个抽象,然后下面可以用iBatis实现,也可以用Hibernate来实现,再以同样的服务发布出去
2 楼 lymalf 2013-06-08  
你可以把ibatis发布成一个服务。这样其他的bundle就都可以调用了。
1 楼 lymalf 2013-06-08  
文章写得很好。我们是把openJPA集成到OSGi中。原理和你的一样

相关推荐

    osgi-ibatis

    描述中提到"一个osgi集成ibatis的例子,我也是在网上下载的",这表明这个压缩包可能包含了一个完整的项目,用于演示如何在OSGi环境下配置和使用iBatis。这通常包括了配置文件、服务接口、实现类以及必要的依赖库。 ...

    osgi数据库连接demo

    在这个“osgi数据库连接demo”中,我们将探讨如何在OSGi环境中配置C3P0作为Oracle数据库连接池,并集成iBATIS作为数据访问层。 首先,C3P0是一个开源的JDBC连接池,它提供了一些额外的功能,如自动管理数据库连接、...

    OSGi原理与实践

    - 支持多种ORM工具,如JDO、Hibernate和iBatis SQL Map。 - 通过统一的事务管理和异常处理机制,使得ORM工具之间的切换变得简单。 6. **Spring Web**: - 为基于Web的应用程序提供了一个强大的上下文环境。 - ...

    hibernate与ibatis比较的11大优势

    相比之下,iBatis虽然也可以与Spring框架集成,但在集成的深度和广度上不如Hibernate。 9. **与JBoss等容器的兼容性**:由于Hibernate遵循JSR 250规范,因此它能够很好地与其他Java EE容器(如JBoss)进行集成。...

    『原创』OSGI研究笔记1 - Equinox ServletBridge模式下调用Datasource

    标题中的“OSGI研究笔记1 - Equinox ServletBridge模式下调用Datasource”表明了这篇文章将探讨如何在OSGI(Open Service Gateway ...对于理解OSGI环境下的服务集成和数据库访问,这个主题具有很高的实践价值。

    sping lib架包

    8. **Spring OSGi**:提供了对OSGi(Open Service Gateway Initiative)服务的集成,使得Spring应用能在OSGi容器中运行。 9. **Spring Test**:这个模块提供了对Spring应用的测试支持,包括单元测试和集成测试,...

    shan2006 (1)【搜狗文档翻译_译文_英译中】1

    - 组件框架:用于对象关系映射,如Hibernate、iBatis和Cayenne。 - 服务框架:面向服务计算的模型,如语义网服务框架。 - 开发框架:用于构建富客户端开发工具,如Eclipse、NetBeans和OSGi。 3. 网络应用框架(WAF...

    Spring PPT文档

    4. **对象/关系映射(ORM Module)**:Spring集成了多种ORM框架,如JDO、Hibernate和iBatis,使得开发者能将这些ORM技术与Spring的其他功能(如事务管理)结合使用,提高了代码的可维护性和可测试性。 5. **面向切面...

    spring 3.0 jar 所有开发包及开发项目实例

    spring 3.0已经全面支持OSGi了。 各发行包的大致描述如下: org.springframework.asm-3.0.0.M4.jar: 提供对ASM(一个字节码框架)的简单封装 org.springframework.expression-3.0.0.M4.jar: spring表达式语言 ...

    OpenStaff-开源

    2. **数据库集成**:OpenStaff 使用数据库来存储员工数据,可能包括 MySQL 或其他关系型数据库。数据库的配置和操作是通过 iBatis 这样的持久层框架完成的,它简化了 SQL 查询的编写和执行。 3. **iBatis 配置**:...

    JAVA开源软件分类

    - **Hibernate/Ibatis/JPA**:这些工具提供了对象关系映射(ORM)的支持,简化了数据库操作。 - **P2:扩展框架** - **OSGi**:为Java平台定义了一个动态模块系统,Equinox 和 SpringDM 是其中两个实现。 - **SOA...

    Spring 2.5 jar 所有开发包及完整文档及项目开发实例

    可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI所需的全部类,UI方面的用来与模板(Templating)引擎如 Velocity、FreeMarker、JasperReports集成的类,以及校验Validation方面的相关类。...

    java技术体系图

    - **WebService、SOA、SCA、ESB、OSGI、EAI**:构建服务化的企业级应用。 综上所述,从Java程序员到Java EE系统架构师,不仅涵盖了Java语言的基础和高级特性,还包括了Web开发、企业级应用框架、分布式计算等多个...

Global site tag (gtag.js) - Google Analytics