这一节将对Dao Interface Bundle 和 Dao implementation Bundle进行开发。

上图是Dao层的设计。为了尽可能的还原真实的设计架构,这里设计了一个BaseDao,用来定义最基本的Dao操作。
然后有一个HibernateBaseDao的抽象类继承它并实现这些基本操作。然后定义了一个ContactDao,这个dao就是联系人相关业务的Dao接口,以及它的实现ContactDaoImpl。图中我们可以看到模块的划分情况,接口是一个bundle,实现是另一个bundle。
- Dao Interface Bundle的开发
(1)首先创建一个Bundle Project项目(创建的详细过程已经在前面的章节给出,请参考前面),定义项目名称为net.georgezeng.test.dao。
(2)定义上面图中的两个接口
BaseDao的定义:
package net.georgezeng.test.dao;
import java.util.List;
public interface BaseDao<T> {
void save(T t);
T get(Long id);
List<T> findList(T t);
}
ContactDao的定义如下:
package net.georgezeng.test.dao;
import net.georgezeng.test.domain.Contact;
public interface ContactDao extends BaseDao<Contact> {
}
(3)MANIFEST.MF的定义
import:
当前的Bundle中有用到了domain bundle下的包,因此需要引入net.georgezeng.test.domain,如图

export:
我们还需要把接口进行export才能让Dao Implementation Bundle进行引用,如图

注意:这里在引入的时候可能会有问题,因为bundle的引用默认是通过在Virgo server的repository目录中获取的,但是目前我们自己开发的bundle是不可能放在那个目录下面的,这个时候就没办法找到那个需要import的包了,所以我们需要做一点小操作,让IDE可以找到这个包。具体操作步骤如下:
1)在Package Explorer中选中当前的项目,如图

我这里的项目名称是net.georgezeng.test.dao2, 然后右键点击弹出菜单,选择最下面的Properties选项,进入下图

选中Project References,然后在勾选上net.georgezeng.test.domain进行项目关联,这样就可以使import搜索到需要的package了。
2)这个应该是属于IDE工具本身的一个小bug,有的时候我们引入项目关联后虽然可以import需要的包了,但是还是提示找不到这个包,这个时候我们可以先将之前已经import的内容remove,再重新import一次就可以了。(后面讲到的项目间的引用都是通过这种方式实现)
这样我们的Dao Interface Bundle就开发完毕了,接下来我们来开发Dao Implementation Bundle
- Dao Implementation Bundle
新建Bundle Projecton工程,命名为net.georgezeng.test.dao.impl。
(1)Dao的实现
(1.1)HibernateBaseDao的定义
package net.georgezeng.test.dao.hibernate;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import net.georgezeng.test.dao.BaseDao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public abstract class HibernateBaseDao<T> extends HibernateDaoSupport implements BaseDao<T> {
protected Class<T> entityClass;
@Autowired
public void init(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
public HibernateBaseDao() {
entityClass = getEntityClass();
}
@Override
public void save(T t) {
getHibernateTemplate().save(t);
}
@Override
public T get(Long id) {
return getHibernateTemplate().get(entityClass, id);
}
@SuppressWarnings("unchecked")
@Override
public List<T> findList(T t) {
return getHibernateTemplate().findByExample(t);
}
@SuppressWarnings("unchecked")
protected Class<T> getEntityClass() {
Type type = getClass().getGenericSuperclass();
Class<T> result = null;
if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
result = (Class<T>) pType.getActualTypeArguments()[0];
}
return result;
}
}
(1.2) ContactDaoImpl的定义
package net.georgezeng.test.contact.dao;
import net.georgezeng.test.dao.ContactDao;
import net.georgezeng.test.dao.hibernate.HibernateBaseDao;
import net.georgezeng.test.domain.Contact;
import org.springframework.stereotype.Repository;
@Repository("ContactDao")
public class ContactDaoImpl extends HibernateBaseDao<Contact> implements ContactDao {
}
这里我们需要给ContactDaoImpl定义一个bean id,这样才能在后面曝露服务的时候引用到这个bean,即@Repository里的"ContactDao"
(2)MANIFEST.MF定义
import:

export: 这个bundle没有需要export的内容
(3)spring配置
(3.1)osgi-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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd" xmlns:osgi="http://www.springframework.org/schema/osgi"> <osgi:reference id="dataSource" interface="javax.sql.DataSource" /> <osgi:service ref="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" context-class-loader="service-provider" /> <osgi:service ref="ContactDao" interface="net.georgezeng.test.dao.ContactDao" /> </beans>
在前面的章节中Datasource Bundle已经曝露了dataSource的服务,这里我们需要引入,通过
<osgi:reference id="dataSource" interface="javax.sql.DataSource" />
我们就把服务引入了
(3.2)appContext.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config /> <context:component-scan base-package="net.georgezeng.test" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource" /> </property> <property name="schemaUpdate" value="false"></property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop> <prop key="hibernate.show_sql">true</prop> <prop key="cache.provider_class">org.hibernate.cache.NoCacheProvider</prop> </props> </property> <property name="annotatedClasses"> <list> <value>net.georgezeng.test.domain.Contact</value> </list> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans>
我们需要定义一个sessionFactory用于对Hibernate进行管理,请看其中对dataSource的引入
<property name="dataSource"> <ref bean="dataSource" /> </property>
这里的bean 属性的值引用的是上面定义的osgi:reference标签中的id属性的值
接着我们还要定义一个transactionManager,用来对事务进行控制。这个transactionManager将会以服务的方式发布到OSGI中,让service层可以使用这个服务。
在回头看osgi-context.xml中对服务的定义,
<osgi:service ref="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" context-class-loader="service-provider" />
这里有一个很重要的属性需要设置,就是context-class-loader,需要设置为service-provider,目的是让service调用这个服务的时候使用的是服务提供者(即Dao Implementation Bundle)的classloader,这样就可以正确的调用hibernate的API,否则将会抛错提示hibernate的API不可见。
其实我们也可以让transactionManager单独作为一个模块,但是意义不大,这里不做讨论。
我们还看到曝露了一个ContactDao的服务,这里ContactDao的id值正是与@Repository中的值相对应的,这样service层就可以使用DAO的服务了
至此dao层的开发就结束了
附上该项目的源码