自JDK1.5后,泛型在很多方面开始应用。DAO层也开始有了基于泛型的开发模式.可能也正因为如此,有不少人认为DAO作为企业级开发的一层可以去掉了,理由就是只要有一个泛型DAO就可以搞定了!而我认为哪怕只有一个DAO,也应算是一个层,层的定义不是由它下面的组件多少决定的,而是由它扮演的角色来决定的。
这里主要就泛型DAO的开发举个例子:
一、泛型DAO的接口
二、定义泛型DAO的实现(这里为Hibernate实现)
注:这里的无参数构造方法在很多文章中都看到了,但我无法成功运用,很遗憾!如果能成功那么就勿须在service中用用那种怪异的构造方法了。另,听说spring3.0已提供了支持泛型的HibernateTemplate,希望能早点看到。
三、在Service层注入并应用泛型DAO
附、Spring框架配置文件(applicationContext.xml)
小结:
虽然我们可以用泛型DAO减少许多代码,但是Dao作为一个层,建议在必要时还是要写各自模块的dao(可以让它继承自泛型dao),这样可以保证逻辑的清晰,方便代码重构!
这里主要就泛型DAO的开发举个例子:
一、泛型DAO的接口
/**
* Generic DAO (Data Access Object) with common methods to CRUD POJOs.
*
* <p>Extend this interface if you want typesafe (no casting necessary) DAO's for your
* domain objects.
*
* @author llf
*/
public interface GenericDao <T, PK extends Serializable> {
public List<T> findByHsql(String hsql);
//为了突出上面的例子方法,以下省掉N多方法,可以在用时再扩展
}
二、定义泛型DAO的实现(这里为Hibernate实现)
/**
* 本dao类基于hibernate,所以需要在applicationContext.xml中定义SessionFacotry
* @author llf
*/
public class BaseDaoHibernate<T, PK extends Serializable> implements GenericDao<T, PK> {
private SessionFactory sessionFactory;
private Class<T> clazz;
@SuppressWarnings("unchecked")
public BaseDaoHibernate() {
//以下代码无法实现,类型转换有错,以后再分析
/*Type type = this.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
clazz = (Class)((ParameterizedType)type).getActualTypeArguments()[0];
} else {
throw new RuntimeException(this.getClass().getName()+ "没有指定继承的po类型");
}*/
}
/**
* 上面无参数构造方法的替代
* 以便在sevice中通过构造为dao指定实体类的类型。不然就无法实现泛型的效果了
*/
@SuppressWarnings("unchecked")
public BaseDaoHibernate(SessionFactory sessionFactory,Class clazz) {
this.sessionFactory = sessionFactory;
this.clazz = clazz;
}
public Class<T> getClazz() {
return clazz;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* 从sessionFactory中取得hibernate的session对象,这是dao的关键因素
*/
public Session getSession() {
return sessionFactory.openSession();
}
/**
* 实现接口中的例子方法
*/
public List<T> findByHsql(String hsql) {
Query queryObject = getSession().createQuery(hsql);
return queryObject.list();
}
}
注:这里的无参数构造方法在很多文章中都看到了,但我无法成功运用,很遗憾!如果能成功那么就勿须在service中用用那种怪异的构造方法了。另,听说spring3.0已提供了支持泛型的HibernateTemplate,希望能早点看到。
三、在Service层注入并应用泛型DAO
/**
*
* @author Administrator
*/
@Service("userManager")
public class UserManagerImpl implements UserManager {
private GenericDao<User, String> baseDao;
/**
* 将sessionFactory注入到dao,并为泛型dao指定实体类型
* @param sessionFactory
*/
@Autowired
private void setSessionFactory(SessionFactory sessionFactory){
baseDao = new BaseDaoHibernate<User,String>(sessionFactory,User.class);
}
/**
* 用这个方法作一个查询操作的例子
*/
public List<User> getAllUsers() {
List<User> users = baseDao.findByHsql("from User user");
return users;
}
//以下省掉N多业务方法……
}
附、Spring框架配置文件(applicationContext.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-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!--组件的自动扫描,主动加载-->
<context:component-scan base-package="cn.lvlf">
<context:include-filter type="regex" expression=".ssh.demo.service.*.*Manager"/>
<context:include-filter type="regex" expression=".ssh.demo.dao.*.*Hibernate"/>
<context:include-filter type="regex" expression=".ssh.demo.web.action.*Action"/>
</context:component-scan>
<!--数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="minPoolSize" value="5"/>
<property name="maxPoolSize" value="30"/>
</bean>
<!--Hibernate的session工厂-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="namingStrategy">
<bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">none</prop>
</props>
</property>
<property name="packagesToScan" >
<list>
<value>cn.lvlf.ssh.demo.model</value>
</list>
</property>
</bean>
<!--定义事务管理组件-->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!--基于注解的事务声明-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
小结:
虽然我们可以用泛型DAO减少许多代码,但是Dao作为一个层,建议在必要时还是要写各自模块的dao(可以让它继承自泛型dao),这样可以保证逻辑的清晰,方便代码重构!